home *** CD-ROM | disk | FTP | other *** search
- Path: xanth!ames!sun-barr!newstop!sun!swap!page
- From: page%swap@Sun.COM (Bob Page)
- Newsgroups: comp.sources.amiga
- Subject: v89i217: rcs - revision control system, Part02/14
- Message-ID: <128093@sun.Eng.Sun.COM>
- Date: 19 Nov 89 09:24:20 GMT
- Sender: news@sun.Eng.Sun.COM
- Lines: 3240
- Approved: page@sun.com
-
- Submitted-by: rsbx@cbmvax.commodore.com (Raymond S. Brand)
- Posting-number: Volume 89, Issue 217
- Archive-name: unix/rcs.02
-
- # This is a shell archive.
- # Remove anything above and including the cut line.
- # Then run the rest of the file through 'sh'.
- # Unpacked files will be owned by you and have default permissions.
- #----cut here-----cut here-----cut here-----cut here----#
- #!/bin/sh
- # shar: SHell ARchive
- # Run the following text through 'sh' to create:
- # diff/analyze.c
- # diff/context.c
- # diff/diff.c
- # diff/diff3.c
- # This is archive 2 of a 14-part kit.
- # This archive created: Sun Nov 19 01:12:04 1989
- if `test ! -d diff`
- then
- mkdir diff
- echo "mkdir diff"
- fi
- echo "extracting diff/analyze.c"
- sed 's/^X//' << \SHAR_EOF > diff/analyze.c
- X/* Analyze file differences for GNU DIFF.
- X Copyright (C) 1988, 1989 Free Software Foundation, Inc.
- X
- XThis file is part of GNU DIFF.
- X
- XGNU DIFF is free software; you can redistribute it and/or modify
- Xit under the terms of the GNU General Public License as published by
- Xthe Free Software Foundation; either version 1, or (at your option)
- Xany later version.
- X
- XGNU DIFF is distributed in the hope that it will be useful,
- Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
- XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- XGNU General Public License for more details.
- X
- XYou should have received a copy of the GNU General Public License
- Xalong with GNU DIFF; see the file COPYING. If not, write to
- Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
- X
- X/* The basic algorithm is described in:
- X "An O(ND) Difference Algorithm and its Variations", Eugene Myers,
- X Algorithmica Vol. 1 No. 2, 1986, p 251. */
- X
- X#include "regex.h"
- X#include "diff.h"
- X
- Xextern int no_discards;
- X
- Xstatic int *xvec, *yvec; /* Vectors being compared. */
- Xstatic int *fdiag; /* Vector, indexed by diagonal, containing
- X the X coordinate of the point furthest
- X along the given diagonal in the forward
- X search of the edit matrix. */
- Xstatic int *bdiag; /* Vector, indexed by diagonal, containing
- X the X coordinate of the point furthest
- X along the given diagonal in the backward
- X search of the edit matrix. */
- X
- X/* Find the midpoint of the shortest edit script for a specified
- X portion of the two files.
- X
- X We scan from the beginnings of the files, and simultaneously from the ends,
- X doing a breadth-first search through the space of edit-sequence.
- X When the two searches meet, we have found the midpoint of the shortest
- X edit sequence.
- X
- X The value returned is the number of the diagonal on which the midpoint lies.
- X The diagonal number equals the number of inserted lines minus the number
- X of deleted lines (counting only lines before the midpoint).
- X The edit cost is stored into *COST; this is the total number of
- X lines inserted or deleted (counting only lines before the midpoint).
- X
- X This function assumes that the first lines of the specified portions
- X of the two files do not match, and likewise that the last lines do not
- X match. The caller must trim matching lines from the beginning and end
- X of the portions it is going to specify.
- X
- X Note that if we return the "wrong" diagonal value, or if
- X the value of bdiag at that diagonal is "wrong",
- X the worst this can do is cause suboptimal diff output.
- X It cannot cause incorrect diff output. */
- X
- Xstatic int
- Xdiag (xoff, xlim, yoff, ylim, cost)
- X int xoff, xlim, yoff, ylim;
- X int *cost;
- X{
- X int *const fd = fdiag; /* Give the compiler a chance. */
- X int *const bd = bdiag; /* Additional help for the compiler. */
- X int *const xv = xvec; /* Still more help for the comiler. */
- X int *const yv = yvec; /* And more and more . . . */
- X const int dmin = xoff - ylim; /* Minimum valid diagonal. */
- X const int dmax = xlim - yoff; /* Maximum valid diagonal. */
- X const int fmid = xoff - yoff; /* Center diagonal of top-down search. */
- X const int bmid = xlim - ylim; /* Center diagonal of bottom-up search. */
- X int fmin = fmid, fmax = fmid; /* Limits of top-down search. */
- X int bmin = bmid, bmax = bmid; /* Limits of bottom-up search. */
- X int c; /* Cost. */
- X int odd = fmid - bmid & 1; /* True if southeast corner is on an odd
- X diagonal with respect to the northwest. */
- X
- X fd[fmid] = xoff;
- X bd[bmid] = xlim;
- X
- X for (c = 1;; ++c)
- X {
- X int d; /* Active diagonal. */
- X int big_snake = 0;
- X
- X /* Extend the top-down search by an edit step in each diagonal. */
- X fmin > dmin ? fd[--fmin - 1] = -1 : ++fmin;
- X fmax < dmax ? fd[++fmax + 1] = -1 : --fmax;
- X for (d = fmax; d >= fmin; d -= 2)
- X {
- X int x, y, oldx, tlo = fd[d - 1], thi = fd[d + 1];
- X
- X if (tlo >= thi)
- X x = tlo + 1;
- X else
- X x = thi;
- X oldx = x;
- X y = x - d;
- X while (x < xlim && y < ylim && xv[x] == yv[y])
- X ++x, ++y;
- X if (x - oldx > 20)
- X big_snake = 1;
- X fd[d] = x;
- X if (odd && bmin <= d && d <= bmax && bd[d] <= fd[d])
- X {
- X *cost = 2 * c - 1;
- X return d;
- X }
- X }
- X
- X /* Similar extend the bottom-up search. */
- X bmin > dmin ? bd[--bmin - 1] = INT_MAX : ++bmin;
- X bmax < dmax ? bd[++bmax + 1] = INT_MAX : --bmax;
- X for (d = bmax; d >= bmin; d -= 2)
- X {
- X int x, y, oldx, tlo = bd[d - 1], thi = bd[d + 1];
- X
- X if (tlo < thi)
- X x = tlo;
- X else
- X x = thi - 1;
- X oldx = x;
- X y = x - d;
- X while (x > xoff && y > yoff && xv[x - 1] == yv[y - 1])
- X --x, --y;
- X if (oldx - x > 20)
- X big_snake = 1;
- X bd[d] = x;
- X if (!odd && fmin <= d && d <= fmax && bd[d] <= fd[d])
- X {
- X *cost = 2 * c;
- X return d;
- X }
- X }
- X
- X /* Heuristic: check occasionally for a diagonal that has made
- X lots of progress compared with the edit distance.
- X If we have any such, find the one that has made the most
- X progress and return it as if it had succeeded.
- X
- X With this heuristic, for files with a constant small density
- X of changes, the algorithm is linear in the file size. */
- X
- X if (c > 200 && big_snake && heuristic)
- X {
- X int best;
- X int bestpos;
- X
- X best = 0;
- X for (d = fmax; d >= fmin; d -= 2)
- X {
- X int dd = d - fmid;
- X if ((fd[d] - xoff)*2 - dd > 12 * (c + (dd > 0 ? dd : -dd)))
- X {
- X if (fd[d] * 2 - dd > best
- X && fd[d] - xoff > 20
- X && fd[d] - d - yoff > 20)
- X {
- X int k;
- X int x = fd[d];
- X
- X /* We have a good enough best diagonal;
- X now insist that it end with a significant snake. */
- X for (k = 1; k <= 20; k++)
- X if (xvec[x - k] != yvec[x - d - k])
- X break;
- X
- X if (k == 21)
- X {
- X best = fd[d] * 2 - dd;
- X bestpos = d;
- X }
- X }
- X }
- X }
- X if (best > 0)
- X {
- X *cost = 2 * c - 1;
- X return bestpos;
- X }
- X
- X best = 0;
- X for (d = bmax; d >= bmin; d -= 2)
- X {
- X int dd = d - bmid;
- X if ((xlim - bd[d])*2 + dd > 12 * (c + (dd > 0 ? dd : -dd)))
- X {
- X if ((xlim - bd[d]) * 2 + dd > best
- X && xlim - bd[d] > 20
- X && ylim - (bd[d] - d) > 20)
- X {
- X /* We have a good enough best diagonal;
- X now insist that it end with a significant snake. */
- X int k;
- X int x = bd[d];
- X
- X for (k = 0; k < 20; k++)
- X if (xvec[x + k] != yvec[x - d + k])
- X break;
- X if (k == 20)
- X {
- X best = (xlim - bd[d]) * 2 + dd;
- X bestpos = d;
- X }
- X }
- X }
- X }
- X if (best > 0)
- X {
- X *cost = 2 * c - 1;
- X return bestpos;
- X }
- X }
- X }
- X}
- X
- X/* Compare in detail contiguous subsequences of the two files
- X which are known, as a whole, to match each other.
- X
- X The results are recorded in the vectors files[N].changed_flag, by
- X storing a 1 in the element for each line that is an insertion or deletion.
- X
- X The subsequence of file 0 is [XOFF, XLIM) and likewise for file 1.
- X
- X Note that XLIM, YLIM are exclusive bounds.
- X All line numbers are origin-0 and discarded lines are not counted. */
- X
- Xstatic void
- Xcompareseq (xoff, xlim, yoff, ylim)
- X int xoff, xlim, yoff, ylim;
- X{
- X /* Slide down the bottom initial diagonal. */
- X while (xoff < xlim && yoff < ylim && xvec[xoff] == yvec[yoff])
- X ++xoff, ++yoff;
- X /* Slide up the top initial diagonal. */
- X while (xlim > xoff && ylim > yoff && xvec[xlim - 1] == yvec[ylim - 1])
- X --xlim, --ylim;
- X
- X /* Handle simple cases. */
- X if (xoff == xlim)
- X while (yoff < ylim)
- X files[1].changed_flag[files[1].realindexes[yoff++]] = 1;
- X else if (yoff == ylim)
- X while (xoff < xlim)
- X files[0].changed_flag[files[0].realindexes[xoff++]] = 1;
- X else
- X {
- X int c, d, f, b;
- X
- X /* Find a point of correspondence in the middle of the files. */
- X
- X d = diag (xoff, xlim, yoff, ylim, &c);
- X f = fdiag[d];
- X b = bdiag[d];
- X
- X if (c == 1)
- X {
- X /* This should be impossible, because it implies that
- X one of the two subsequences is empty,
- X and that case was handled above without calling `diag'.
- X Let's verify that this is true. */
- X abort ();
- X#if 0
- X /* The two subsequences differ by a single insert or delete;
- X record it and we are done. */
- X if (d < xoff - yoff)
- X files[1].changed_flag[files[1].realindexes[b - d - 1]] = 1;
- X else
- X files[0].changed_flag[files[0].realindexes[b]] = 1;
- X#endif
- X }
- X else
- X {
- X /* Use that point to split this problem into two subproblems. */
- X compareseq (xoff, b, yoff, b - d);
- X /* This used to use f instead of b,
- X but that is incorrect!
- X It is not necessarily the case that diagonal d
- X has a snake from b to f. */
- X compareseq (b, xlim, b - d, ylim);
- X }
- X }
- X}
- X
- X/* Discard lines from one file that have no matches in the other file.
- X
- X A line which is discarded will not be considered by the actual
- X comparison algorithm; it will be as if that line were not in the file.
- X The file's `realindexes' table maps virtual line numbers
- X (which don't count the discarded lines) into real line numbers;
- X this is how the actual comparison algorithm produces results
- X that are comprehensible when the discarded lines are counted.
- X
- X When we discard a line, we also mark it as a deletion or insertion
- X so that it will be printed in the output. */
- X
- Xvoid
- Xdiscard_confusing_lines (filevec)
- X struct file_data filevec[];
- X{
- X int f, i, j;
- X char *discarded[2];
- X int *equiv_count[2];
- X
- X /* Allocate our results. */
- X for (f = 0; f < 2; f++)
- X {
- X filevec[f].undiscarded
- X = (int *) xmalloc (filevec[f].buffered_lines * sizeof (int));
- X filevec[f].realindexes
- X = (int *) xmalloc (filevec[f].buffered_lines * sizeof (int));
- X }
- X
- X /* Set up equiv_count[F][I] as the number of lines in file F
- X that fall in equivalence class I. */
- X
- X equiv_count[0] = (int *) xmalloc (filevec[0].equiv_max * sizeof (int));
- X bzero (equiv_count[0], filevec[0].equiv_max * sizeof (int));
- X equiv_count[1] = (int *) xmalloc (filevec[1].equiv_max * sizeof (int));
- X bzero (equiv_count[1], filevec[1].equiv_max * sizeof (int));
- X
- X for (i = 0; i < filevec[0].buffered_lines; ++i)
- X ++equiv_count[0][filevec[0].equivs[i]];
- X for (i = 0; i < filevec[1].buffered_lines; ++i)
- X ++equiv_count[1][filevec[1].equivs[i]];
- X
- X /* Set up tables of which lines are going to be discarded. */
- X
- X discarded[0] = (char *) xmalloc (filevec[0].buffered_lines);
- X discarded[1] = (char *) xmalloc (filevec[1].buffered_lines);
- X bzero (discarded[0], filevec[0].buffered_lines);
- X bzero (discarded[1], filevec[1].buffered_lines);
- X
- X /* Mark to be discarded each line that matches no line of the other file.
- X If a line matches many lines, mark it as provisionally discardable. */
- X
- X for (f = 0; f < 2; f++)
- X {
- X int end = filevec[f].buffered_lines;
- X char *discards = discarded[f];
- X int *counts = equiv_count[1 - f];
- X int *equivs = filevec[f].equivs;
- X for (i = 0; i < end; i++)
- X {
- X int nmatch = counts[equivs[i]];
- X if (equivs[i] == 0)
- X continue;
- X if (nmatch == 0)
- X discards[i] = 1;
- X else if (nmatch > 5)
- X discards[i] = 2;
- X }
- X }
- X
- X /* Don't really discard the provisional lines if there are less than ten
- X discardable lines in a row. */
- X
- X for (f = 0; f < 2; f++)
- X {
- X int end = filevec[f].buffered_lines;
- X char *discards = discarded[f];
- X
- X for (i = 0; i < end; i++)
- X if (discards[i])
- X {
- X register int j;
- X int length;
- X int provisional = 0;
- X
- X /* Cancel provisional discards at the beginning. */
- X while (i < end && discards[i] == 2)
- X discards[i] = 0;
- X
- X /* Find end of this run of discardable lines.
- X Count how many are provisionally discardable. */
- X for (j = i; j < end; j++)
- X {
- X if (discards[j] == 0)
- X break;
- X if (discards[j] == 2)
- X ++provisional;
- X }
- X
- X /* Cancel provisional discards at the end, and shrink the run. */
- X while (j > i && discards[j - 1] == 2)
- X discards[j - 1] = 0, --provisional;
- X
- X /* Now we have the length of a run of discardable lines
- X whose first and last are not provisional. */
- X length = j - i;
- X
- X /* If half the lines in the run are provisional,
- X cancel discarding of all provisional lines in the run. */
- X if (provisional * 2 > length)
- X {
- X while (j > i)
- X if (discards[--j] == 2)
- X discards[j] = 0;
- X }
- X else
- X {
- X /* Cancel provisional discards that are near either end. */
- X for (j = 0; j < 5 && j < length; j++)
- X if (discards[i + j] == 2)
- X discards[i + j] = 0;
- X /* Meanwhile, I advances to the last line of the run. */
- X i += length - 1;
- X length -= 5;
- X for (j = 0; j < 5 && j < length; j++)
- X if (discards[i - j] == 2)
- X discards[i - j] = 0;
- X }
- X }
- X }
- X
- X /* Discard from file 0. */
- X for (f = 0; f < 2; f++)
- X {
- X char *discards = discarded[f];
- X int end = filevec[f].buffered_lines;
- X j = 0;
- X for (i = 0; i < end; ++i)
- X if (no_discards || discards[i] == 0)
- X {
- X filevec[f].undiscarded[j] = filevec[f].equivs[i];
- X filevec[f].realindexes[j++] = i;
- X }
- X else
- X filevec[f].changed_flag[i] = 1;
- X filevec[f].nondiscarded_lines = j;
- X }
- X
- X free (discarded[1]);
- X free (discarded[0]);
- X free (equiv_count[1]);
- X free (equiv_count[0]);
- X}
- X
- X/* Adjust inserts/deletes of blank lines to join changes
- X as much as possible.
- X
- X We do something when a run of changed lines include a blank
- X line at one end and have an excluded blank line at the other.
- X We are free to choose which blank line is included.
- X `compareseq' always chooses the one at the beginning,
- X but usually it is cleaner to consider the following blank line
- X to be the "change". The only exception is if the preceding blank line
- X would join this change to other changes. */
- X
- Xint inhibit;
- X
- Xstatic void
- Xshift_boundaries (filevec)
- X struct file_data filevec[];
- X{
- X int f;
- X
- X if (inhibit)
- X return;
- X
- X for (f = 0; f < 2; f++)
- X {
- X char *changed = filevec[f].changed_flag;
- X char *other_changed = filevec[1-f].changed_flag;
- X int i = 0;
- X int j = 0;
- X int i_end = filevec[f].buffered_lines;
- X int preceeding = -1;
- X int other_preceeding = -1;
- X
- X while (1)
- X {
- X int start, end, other_start;
- X
- X /* Scan forwards to find beginning of another run of changes.
- X Also keep track of the corresponding point in the other file. */
- X
- X while (i < i_end && changed[i] == 0)
- X {
- X while (other_changed[j++])
- X /* Non-corresponding lines in the other file
- X will count as the preceeding batch of changes. */
- X other_preceeding = j;
- X i++;
- X }
- X
- X if (i == i_end)
- X break;
- X
- X start = i;
- X other_start = j;
- X
- X while (1)
- X {
- X /* Now find the end of this run of changes. */
- X
- X while (i < i_end && changed[i] != 0) i++;
- X end = i;
- X
- X /* If the first changed line matches the following unchanged one,
- X and this run does not follow right after a previous run,
- X and there are no lines deleted from the other file here,
- X then classify the first changed line as unchanged
- X and the following line as changed in its place. */
- X
- X /* You might ask, how could this run follow right after another?
- X Only because the previous run was shifted here. */
- X
- X if (files[f].equivs[start] == files[f].equivs[end]
- X && !other_changed[j]
- X && end != i_end
- X && !((preceeding >= 0 && start == preceeding)
- X || (other_preceeding >= 0
- X && other_start == other_preceeding)))
- X {
- X changed[end++] = 1;
- X changed[start++] = 0;
- X ++i;
- X /* Since one line-that-matches is now before this run
- X instead of after, we must advance in the other file
- X to keep in synch. */
- X ++j;
- X }
- X else
- X break;
- X }
- X
- X preceeding = i;
- X other_preceeding = j;
- X }
- X }
- X}
- X
- X/* Cons an additional entry onto the front of an edit script OLD.
- X LINE0 and LINE1 are the first affected lines in the two files (origin 0).
- X DELETED is the number of lines deleted here from file 0.
- X INSERTED is the number of lines inserted here in file 1.
- X
- X If DELETED is 0 then LINE0 is the number of the line before
- X which the insertion was done; vice versa for INSERTED and LINE1. */
- X
- Xstatic struct change *
- Xadd_change (line0, line1, deleted, inserted, old)
- X int line0, line1, deleted, inserted;
- X struct change *old;
- X{
- X struct change *new = (struct change *) xmalloc (sizeof (struct change));
- X
- X new->line0 = line0;
- X new->line1 = line1;
- X new->inserted = inserted;
- X new->deleted = deleted;
- X new->link = old;
- X return new;
- X}
- X
- X/* Scan the tables of which lines are inserted and deleted,
- X producing an edit script in reverse order. */
- X
- Xstatic struct change *
- Xbuild_reverse_script (filevec)
- X struct file_data filevec[];
- X{
- X struct change *script = 0;
- X char *changed0 = filevec[0].changed_flag;
- X char *changed1 = filevec[1].changed_flag;
- X int len0 = filevec[0].buffered_lines;
- X int len1 = filevec[1].buffered_lines;
- X
- X /* Note that changedN[len0] does exist, and contains 0. */
- X
- X int i0 = 0, i1 = 0;
- X
- X while (i0 < len0 || i1 < len1)
- X {
- X if (changed0[i0] || changed1[i1])
- X {
- X int line0 = i0, line1 = i1;
- X
- X /* Find # lines changed here in each file. */
- X while (changed0[i0]) ++i0;
- X while (changed1[i1]) ++i1;
- X
- X /* Record this change. */
- X script = add_change (line0, line1, i0 - line0, i1 - line1, script);
- X }
- X
- X /* We have reached lines in the two files that match each other. */
- X i0++, i1++;
- X }
- X
- X return script;
- X}
- X
- X/* Scan the tables of which lines are inserted and deleted,
- X producing an edit script in forward order. */
- X
- Xstatic struct change *
- Xbuild_script (filevec)
- X struct file_data filevec[];
- X{
- X struct change *script = 0;
- X char *changed0 = filevec[0].changed_flag;
- X char *changed1 = filevec[1].changed_flag;
- X int len0 = filevec[0].buffered_lines;
- X int len1 = filevec[1].buffered_lines;
- X
- X /* Note that changedN[-1] does exist, and contains 0. */
- X
- X int i0 = len0, i1 = len1;
- X
- X while (i0 >= 0 || i1 >= 0)
- X {
- X if (changed0[i0 - 1] || changed1[i1 - 1])
- X {
- X int line0 = i0, line1 = i1;
- X
- X /* Find # lines changed here in each file. */
- X while (changed0[i0 - 1]) --i0;
- X while (changed1[i1 - 1]) --i1;
- X
- X /* Record this change. */
- X script = add_change (i0, i1, line0 - i0, line1 - i1, script);
- X }
- X
- X /* We have reached lines in the two files that match each other. */
- X i0--, i1--;
- X }
- X
- X return script;
- X}
- X
- X/* Report the differences of two files. DEPTH is the current directory
- X depth. */
- Xint
- Xdiff_2_files (filevec, depth)
- X struct file_data filevec[];
- X int depth;
- X{
- X int diags;
- X int i;
- X struct change *e, *p;
- X struct change *script;
- X int binary;
- X
- X /* See if the two named files are actually the same physical file.
- X If so, we know they are identical without actually reading them. */
- X
- X#ifndef AMIGA
- X if (filevec[0].stat.st_ino == filevec[1].stat.st_ino
- X && filevec[0].stat.st_dev == filevec[1].stat.st_dev)
- X return 0;
- X#endif
- X
- X binary = read_files (filevec);
- X
- X /* If we have detected that file 0 is a binary file,
- X compare the two files as binary. This can happen
- X only when the first chunk is read. */
- X
- X if (binary)
- X {
- X int differs = (filevec[0].buffered_chars != filevec[1].buffered_chars
- X || bcmp (filevec[0].buffer, filevec[1].buffer,
- X filevec[1].buffered_chars));
- X if (differs)
- X message ("Binary files %s and %s differ\n",
- X filevec[0].name, filevec[1].name);
- X
- X for (i = 0; i < 2; ++i)
- X if (filevec[i].buffer)
- X free (filevec[i].buffer);
- X return differs;
- X }
- X
- X if (filevec[0].missing_newline != filevec[1].missing_newline)
- X {
- X if (filevec[0].missing_newline)
- X error ("No newline at end of file %s\n", filevec[0].name);
- X if (filevec[1].missing_newline)
- X error ("No newline at end of file %s\n", filevec[1].name);
- X }
- X
- X /* Allocate vectors for the results of comparison:
- X a flag for each line of each file, saying whether that line
- X is an insertion or deletion.
- X Allocate an extra element, always zero, at each end of each vector. */
- X
- X filevec[0].changed_flag = (char *) xmalloc (filevec[0].buffered_lines + 2);
- X filevec[1].changed_flag = (char *) xmalloc (filevec[1].buffered_lines + 2);
- X bzero (filevec[0].changed_flag, filevec[0].buffered_lines + 2);
- X bzero (filevec[1].changed_flag, filevec[1].buffered_lines + 2);
- X filevec[0].changed_flag++;
- X filevec[1].changed_flag++;
- X
- X /* Some lines are obviously insertions or deletions
- X because they don't match anything. Detect them now,
- X and avoid even thinking about them in the main comparison algorithm. */
- X
- X discard_confusing_lines (filevec);
- X
- X /* Now do the main comparison algorithm, considering just the
- X undiscarded lines. */
- X
- X xvec = filevec[0].undiscarded;
- X yvec = filevec[1].undiscarded;
- X diags = filevec[0].nondiscarded_lines + filevec[1].nondiscarded_lines + 3;
- X fdiag = (int *) xmalloc (diags * sizeof (int));
- X fdiag += filevec[1].nondiscarded_lines + 1;
- X bdiag = (int *) xmalloc (diags * sizeof (int));
- X bdiag += filevec[1].nondiscarded_lines + 1;
- X
- X files[0] = filevec[0];
- X files[1] = filevec[1];
- X
- X compareseq (0, filevec[0].nondiscarded_lines,
- X 0, filevec[1].nondiscarded_lines);
- X
- X bdiag -= filevec[1].nondiscarded_lines + 1;
- X free (bdiag);
- X fdiag -= filevec[1].nondiscarded_lines + 1;
- X free (fdiag);
- X
- X /* Modify the results slightly to make them prettier
- X in cases where that can validly be done. */
- X
- X shift_boundaries (filevec);
- X
- X /* Get the results of comparison in the form of a chain
- X of `struct change's -- an edit script. */
- X
- X if (output_style == OUTPUT_ED)
- X script = build_reverse_script (filevec);
- X else
- X script = build_script (filevec);
- X
- X if (script)
- X {
- X setup_output (files[0].name, files[1].name, depth);
- X if (output_style == OUTPUT_CONTEXT)
- X print_context_header (files);
- X
- X switch (output_style)
- X {
- X case OUTPUT_CONTEXT:
- X print_context_script (script);
- X break;
- X
- X case OUTPUT_ED:
- X print_ed_script (script);
- X break;
- X
- X case OUTPUT_FORWARD_ED:
- X pr_forward_ed_script (script);
- X break;
- X
- X case OUTPUT_RCS:
- X print_rcs_script (script);
- X break;
- X
- X case OUTPUT_NORMAL:
- X print_normal_script (script);
- X break;
- X }
- X
- X finish_output ();
- X }
- X
- X for (i = 1; i >= 0; --i)
- X {
- X free (filevec[i].realindexes);
- X free (filevec[i].undiscarded);
- X }
- X
- X for (i = 1; i >= 0; --i)
- X free (--filevec[i].changed_flag);
- X
- X for (i = 1; i >= 0; --i)
- X free (filevec[i].equivs);
- X
- X for (i = 0; i < 2; ++i)
- X {
- X if (filevec[i].buffer != 0)
- X free (filevec[i].buffer);
- X free (filevec[i].linbuf);
- X }
- X
- X for (e = script; e; e = p)
- X {
- X p = e->link;
- X free (e);
- X }
- X
- X return script ? 1 : 0;
- X}
- SHAR_EOF
- echo "extracting diff/context.c"
- sed 's/^X//' << \SHAR_EOF > diff/context.c
- X/* Context-format output routines for GNU DIFF.
- X Copyright (C) 1988, 1989 Free Software Foundation, Inc.
- X
- XThis file is part of GNU DIFF.
- X
- XGNU DIFF is free software; you can redistribute it and/or modify
- Xit under the terms of the GNU General Public License as published by
- Xthe Free Software Foundation; either version 1, or (at your option)
- Xany later version.
- X
- XGNU DIFF is distributed in the hope that it will be useful,
- Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
- XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- XGNU General Public License for more details.
- X
- XYou should have received a copy of the GNU General Public License
- Xalong with GNU DIFF; see the file COPYING. If not, write to
- Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
- X
- X#include "diff.h"
- X
- Xstatic void pr_context_hunk ();
- Xstatic struct change *find_hunk ();
- Xstatic void mark_ignorable ();
- Xstatic int find_function ();
- X
- X/* Last place find_function started searching from. */
- Xstatic int find_function_last_search;
- X
- X/* The value find_function returned when it started searching there. */
- Xstatic int find_function_last_match;
- X
- X/* Print a header for a context diff, with the file names and dates. */
- X
- Xvoid
- Xprint_context_header (inf)
- X struct file_data *inf;
- X{
- X fprintf (outfile, "*** %s\t%s", inf[0].name,
- X ctime (&inf[0].stat.st_mtime));
- X fprintf (outfile, "--- %s\t%s", inf[1].name,
- X ctime (&inf[1].stat.st_mtime));
- X}
- X
- X/* Print an edit script in context format. */
- X
- Xvoid
- Xprint_context_script (script)
- X struct change *script;
- X{
- X if (ignore_blank_lines_flag || ignore_regexp)
- X mark_ignorable (script);
- X else
- X {
- X struct change *e;
- X for (e = script; e; e = e->link)
- X e->ignore = 0;
- X }
- X
- X find_function_last_search = 0;
- X find_function_last_match = -1;
- X
- X print_script (script, find_hunk, pr_context_hunk);
- X}
- X
- X/* Print a pair of line numbers with a comma, translated for file FILE.
- X If the second number is smaller, use the first in place of it.
- X
- X Args A and B are internal line numbers.
- X We print the translated (real) line numbers. */
- X
- Xstatic void
- Xprint_context_number_range (file, a, b)
- X struct file_data *file;
- X int a, b;
- X{
- X int trans_a, trans_b;
- X translate_range (file, a, b, &trans_a, &trans_b);
- X
- X /* Note: we can have B < A in the case of a range of no lines.
- X In this case, we should print the line number before the range,
- X which is B. */
- X if (trans_b >= trans_a)
- X fprintf (outfile, "%d,%d", trans_a, trans_b);
- X else
- X fprintf (outfile, "%d", trans_b);
- X}
- X
- X/* Print a portion of an edit script in context format.
- X HUNK is the beginning of the portion to be printed.
- X The end is marked by a `link' that has been nulled out.
- X
- X Prints out lines from both files, and precedes each
- X line with the appropriate flag-character. */
- X
- Xstatic void
- Xpr_context_hunk (hunk)
- X struct change *hunk;
- X{
- X int first0, last0, first1, last1, show_from, show_to, i;
- X struct change *next;
- X char *prefix;
- X char *function;
- X int function_length;
- X
- X /* Determine range of line numbers involved in each file. */
- X
- X analyze_hunk (hunk, &first0, &last0, &first1, &last1, &show_from, &show_to);
- X
- X if (!show_from && !show_to)
- X return;
- X
- X /* Include a context's width before and after. */
- X
- X first0 = max (first0 - context, 0);
- X first1 = max (first1 - context, 0);
- X last0 = min (last0 + context, files[0].buffered_lines - 1);
- X last1 = min (last1 + context, files[1].buffered_lines - 1);
- X
- X /* If desired, find the preceding function definition line in file 0. */
- X function = 0;
- X if (function_regexp)
- X find_function (&files[0], first0, &function, &function_length);
- X
- X /* If we looked for and found a function this is part of,
- X include its name in the header of the diff section. */
- X fprintf (outfile, "***************");
- X
- X if (function)
- X {
- X fprintf (outfile, " ");
- X fwrite (function, 1, min (function_length - 1, 40), outfile);
- X }
- X
- X fprintf (outfile, "\n*** ");
- X print_context_number_range (&files[0], first0, last0);
- X fprintf (outfile, " ****\n");
- X
- X if (show_from)
- X {
- X next = hunk;
- X
- X for (i = first0; i <= last0; i++)
- X {
- X /* Skip past changes that apply (in file 0)
- X only to lines before line I. */
- X
- X while (next && next->line0 + next->deleted <= i)
- X next = next->link;
- X
- X /* Compute the marking for line I. */
- X
- X prefix = " ";
- X if (next && next->line0 <= i)
- X /* The change NEXT covers this line.
- X If lines were inserted here in file 1, this is "changed".
- X Otherwise it is "deleted". */
- X prefix = (next->inserted > 0 ? "!" : "-");
- X
- X print_1_line (prefix, &files[0].linbuf[i]);
- X }
- X }
- X
- X fprintf (outfile, "--- ");
- X print_context_number_range (&files[1], first1, last1);
- X fprintf (outfile, " ----\n");
- X
- X if (show_to)
- X {
- X next = hunk;
- X
- X for (i = first1; i <= last1; i++)
- X {
- X /* Skip past changes that apply (in file 1)
- X only to lines before line I. */
- X
- X while (next && next->line1 + next->inserted <= i)
- X next = next->link;
- X
- X /* Compute the marking for line I. */
- X
- X prefix = " ";
- X if (next && next->line1 <= i)
- X /* The change NEXT covers this line.
- X If lines were deleted here in file 0, this is "changed".
- X Otherwise it is "inserted". */
- X prefix = (next->deleted > 0 ? "!" : "+");
- X
- X print_1_line (prefix, &files[1].linbuf[i]);
- X }
- X }
- X}
- X
- X/* Scan a (forward-ordered) edit script for the first place that at least
- X 2*CONTEXT unchanged lines appear, and return a pointer
- X to the `struct change' for the last change before those lines. */
- X
- Xstatic struct change *
- Xfind_hunk (start)
- X struct change *start;
- X{
- X struct change *prev;
- X int top0, top1;
- X int thresh;
- X
- X do
- X {
- X /* Computer number of first line in each file beyond this changed. */
- X top0 = start->line0 + start->deleted;
- X top1 = start->line1 + start->inserted;
- X prev = start;
- X start = start->link;
- X /* Threshold distance is 2*CONTEXT between two non-ignorable changes,
- X but only CONTEXT if one is ignorable. */
- X thresh = ((prev->ignore || (start && start->ignore))
- X ? context
- X : 2 * context);
- X /* It is not supposed to matter which file we check in the end-test.
- X If it would matter, crash. */
- X if (start && start->line0 - top0 != start->line1 - top1)
- X abort ();
- X } while (start
- X /* Keep going if less than THRESH lines
- X elapse before the affected line. */
- X && start->line0 < top0 + thresh);
- X
- X return prev;
- X}
- X
- X/* Set the `ignore' flag properly in each change in SCRIPT.
- X It should be 1 if all the lines inserted or deleted in that change
- X are ignorable lines. */
- X
- Xstatic void
- Xmark_ignorable (script)
- X struct change *script;
- X{
- X while (script)
- X {
- X struct change *next = script->link;
- X int first0, last0, first1, last1, deletes, inserts;
- X
- X /* Turn this change into a hunk: detach it from the others. */
- X script->link = 0;
- X
- X /* Determine whether this change is ignorable. */
- X analyze_hunk (script, &first0, &last0, &first1, &last1, &deletes, &inserts);
- X /* Reconnect the chain as before. */
- X script->link = next;
- X
- X /* If the change is ignorable, mark it. */
- X script->ignore = (!deletes && !inserts);
- X
- X /* Advance to the following change. */
- X script = next;
- X }
- X}
- X
- X/* Find the last function-header line in FILE prior to line number LINENUM.
- X This is a line containing a match for the regexp in `function_regexp'.
- X Store the address of the line text into LINEP and the length of the
- X line into LENP.
- X Do not store anything if no function-header is found. */
- X
- Xstatic int
- Xfind_function (file, linenum, linep, lenp)
- X struct file_data *file;
- X int linenum;
- X char **linep;
- X int *lenp;
- X{
- X int i = linenum;
- X int last = find_function_last_search;
- X find_function_last_search = i;
- X
- X while (--i >= last)
- X {
- X /* See if this line is what we want. */
- X
- X if (0 <= re_search (&function_regexp_compiled,
- X files[0].linbuf[i].text,
- X files[0].linbuf[i].length,
- X 0, files[0].linbuf[i].length,
- X 0))
- X {
- X *linep = files[0].linbuf[i].text;
- X *lenp = files[0].linbuf[i].length;
- X find_function_last_match = i;
- X return 1;
- X }
- X }
- X /* If we search back to where we started searching the previous time,
- X find the line we found last time. */
- X if (find_function_last_match >= 0)
- X {
- X i = find_function_last_match;
- X *linep = files[0].linbuf[i].text;
- X *lenp = files[0].linbuf[i].length;
- X return 1;
- X }
- X return 0;
- X}
- SHAR_EOF
- echo "extracting diff/diff.c"
- sed 's/^X//' << \SHAR_EOF > diff/diff.c
- X/* GNU DIFF main routine.
- X Copyright (C) 1988, 1989 Free Software Foundation, Inc.
- X
- XThis file is part of GNU DIFF.
- X
- XGNU DIFF is free software; you can redistribute it and/or modify
- Xit under the terms of the GNU General Public License as published by
- Xthe Free Software Foundation; either version 1, or (at your option)
- Xany later version.
- X
- XGNU DIFF is distributed in the hope that it will be useful,
- Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
- XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- XGNU General Public License for more details.
- X
- XYou should have received a copy of the GNU General Public License
- Xalong with GNU DIFF; see the file COPYING. If not, write to
- Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
- X
- X/* GNU DIFF was written by Mike Haertel, David Hayes,
- X Richard Stallman and Len Tower. */
- X
- X#define GDIFF_MAIN
- X#include "regex.h"
- X#include "diff.h"
- X
- X
- X/* Nonzero for -r: if comparing two directories,
- X compare their common subdirectories recursively. */
- X
- Xint recursive;
- X
- X/* For debugging: don't do discard_confusing_lines. */
- X
- Xint no_discards;
- X
- Xvoid specify_style();
- X
- X/* Return a string containing the command options with which diff was invoked.
- X Spaces appear between what were separate ARGV-elements.
- X There is a space at the beginning but none at the end.
- X If there were no options, the result is an empty string.
- X
- X Arguments: VECTOR, a vector containing separate ARGV-elements, and COUNT,
- X the length of that vector. */
- X
- Xstatic char *
- Xoption_list (vector, count)
- X char **vector;
- X int count;
- X{
- X int i;
- X int length = 0;
- X char *result;
- X
- X for (i = 0; i < count; i++)
- X length += strlen (vector[i]) + 1;
- X
- X result = (char *) xmalloc (length + 1);
- X result[0] = 0;
- X
- X for (i = 0; i < count; i++)
- X {
- X strcat (result, " ");
- X strcat (result, vector[i]);
- X }
- X
- X return result;
- X}
- X
- Xmain (argc, argv)
- X int argc;
- X char *argv[];
- X{
- X int val;
- X int c;
- X int prev = -1;
- X
- X extern int optind;
- X extern char *optarg;
- X
- X program = argv[0];
- X
- X /* Do our initializations. */
- X output_style = OUTPUT_NORMAL;
- X always_text_flag = FALSE;
- X ignore_space_change_flag = FALSE;
- X ignore_all_space_flag = FALSE;
- X length_varies = FALSE;
- X ignore_case_flag = FALSE;
- X ignore_blank_lines_flag = FALSE;
- X ignore_regexp = 0;
- X function_regexp = 0;
- X print_file_same_flag = FALSE;
- X entire_new_file_flag = FALSE;
- X context = -1;
- X line_end_char = '\n';
- X tab_align_flag = FALSE;
- X tab_expand_flag = FALSE;
- X recursive = FALSE;
- X paginate_flag = FALSE;
- X heuristic = FALSE;
- X dir_start_file = NULL;
- X msg_chain = NULL;
- X msg_chain_end = NULL;
- X no_discards = 0;
- X
- X /* Decode the options. */
- X
- X while ((c = getopt (argc, argv, "0123456789abBcC:defF:hHiI:lnNprsS:tTw"))
- X != EOF)
- X {
- X switch (c)
- X {
- X /* All digits combine in decimal to specify the context-size. */
- X case '1':
- X case '2':
- X case '3':
- X case '4':
- X case '5':
- X case '6':
- X case '7':
- X case '8':
- X case '9':
- X case '0':
- X if (context == -1)
- X context = 0;
- X /* If a context length has already been specified,
- X more digits allowed only if they follow right after the others.
- X Reject two separate runs of digits, or digits after -C. */
- X else if (prev < '0' || prev > '9')
- X fatal ("context length specified twice");
- X
- X context = context * 10 + c - '0';
- X break;
- X
- X case 'a':
- X /* Treat all files as text files; never treat as binary. */
- X always_text_flag = 1;
- X break;
- X
- X case 'b':
- X /* Ignore changes in amount of whitespace. */
- X ignore_space_change_flag = 1;
- X length_varies = 1;
- X break;
- X
- X case 'B':
- X /* Ignore changes affecting only blank lines. */
- X ignore_blank_lines_flag = 1;
- X break;
- X
- X case 'c':
- X /* Make context-style output. */
- X specify_style (OUTPUT_CONTEXT);
- X break;
- X
- X case 'C':
- X if (context >= 0)
- X fatal ("context length specified twice");
- X {
- X char *p;
- X for (p = optarg; *p; p++)
- X if (*p < '0' || *p > '9')
- X fatal ("invalid context length argument (-C option)");
- X }
- X context = atoi (optarg);
- X break;
- X
- X case 'd':
- X /* Don't discard lines. This makes things slower (sometimes much
- X slower) but will find a guaranteed minimal set of changes. */
- X no_discards = 1;
- X break;
- X
- X case 'e':
- X /* Make output that is a valid `ed' script. */
- X specify_style (OUTPUT_ED);
- X break;
- X
- X case 'f':
- X /* Make output that looks vaguely like an `ed' script
- X but has changes in the order they appear in the file. */
- X specify_style (OUTPUT_FORWARD_ED);
- X break;
- X
- X case 'F':
- X /* Show, for each set of changes, the previous line that
- X matches the specified regexp. Currently affects only
- X context-style output. */
- X function_regexp = optarg;
- X break;
- X
- X case 'h':
- X /* Split the files into chunks of around 1500 lines
- X for faster processing. Usually does not change the result.
- X
- X This currently has no effect. */
- X break;
- X
- X case 'H':
- X /* Turn on heuristics that speed processing of large files
- X with a small density of changes. */
- X heuristic = 1;
- X break;
- X
- X case 'i':
- X /* Ignore changes in case. */
- X ignore_case_flag = 1;
- X break;
- X
- X case 'I':
- X /* Ignore changes affecting only lines that match the
- X specified regexp. */
- X ignore_regexp = optarg;
- X break;
- X
- X case 'l':
- X /* Pass the output through `pr' to paginate it. */
- X paginate_flag = 1;
- X break;
- X
- X case 'n':
- X /* Output RCS-style diffs, like `-f' except that each command
- X specifies the number of lines affected. */
- X specify_style (OUTPUT_RCS);
- X break;
- X
- X case 'N':
- X /* When comparing directories, if a file appears only in one
- X directory, treat it as present but empty in the other. */
- X entire_new_file_flag = 1;
- X break;
- X
- X case 'p':
- X /* Make context-style output and show name of last C function. */
- X specify_style (OUTPUT_CONTEXT);
- X function_regexp = "^[_a-zA-Z]";
- X break;
- X
- X case 'r':
- X /* When comparing directories,
- X recursively compare any subdirectories found. */
- X recursive = 1;
- X break;
- X
- X case 's':
- X /* Print a message if the files are the same. */
- X print_file_same_flag = 1;
- X break;
- X
- X case 'S':
- X /* When comparing directories, start with the specified
- X file name. This is used for resuming an aborted comparison. */
- X dir_start_file = optarg;
- X break;
- X
- X case 't':
- X /* Expand tabs to spaces in the output so that it preserves
- X the alignment of the input files. */
- X tab_expand_flag = 1;
- X break;
- X
- X case 'T':
- X /* Use a tab in the output, rather than a space, before the
- X text of an input line, so as to keep the proper alignment
- X in the input line without changing the characters in it. */
- X tab_align_flag = 1;
- X break;
- X
- X case 'w':
- X /* Ignore horizontal whitespace when comparing lines. */
- X ignore_all_space_flag = 1;
- X length_varies = 1;
- X break;
- X }
- X prev = c;
- X }
- X
- X if (optind != argc - 2)
- X fatal ("requires two file names. Usage: diff [-options] file1 file2");
- X
- X /*
- X * @@ need more complicated usage string for directory options??
- X * Note three liner at top of BSD documentation, and John Gilmore
- X * message in his public domain tar being used by GNU.
- X */
- X
- X if (ignore_regexp)
- X {
- X char *val;
- X bzero (&ignore_regexp_compiled, sizeof ignore_regexp_compiled);
- X val = re_compile_pattern (ignore_regexp, strlen (ignore_regexp),
- X &ignore_regexp_compiled);
- X if (val != 0)
- X error ("-I option: ", val);
- X ignore_regexp_compiled.fastmap = (char *) xmalloc (256);
- X }
- X
- X if (function_regexp)
- X {
- X char *val;
- X bzero (&function_regexp_compiled, sizeof function_regexp_compiled);
- X val = re_compile_pattern (function_regexp, strlen (function_regexp),
- X &function_regexp_compiled);
- X if (val != 0)
- X error ("-F option: ", val);
- X function_regexp_compiled.fastmap = (char *) xmalloc (256);
- X }
- X
- X if (output_style != OUTPUT_CONTEXT)
- X context = 0;
- X else if (context == -1)
- X /* Default amount of context for -c. */
- X context = 3;
- X
- X switch_string = option_list (argv + 1, optind - 1);
- X
- X val = compare_files (0, argv[optind], 0, argv[optind + 1], 0);
- X
- X /* Print any messages that were saved up for last. */
- X print_message_queue ();
- X
- X exit (val);
- X}
- X
- Xvoid specify_style (style)
- X enum output_style style;
- X{
- X if (output_style != OUTPUT_NORMAL
- X && output_style != style)
- X error ("conflicting specifications of output style");
- X output_style = style;
- X}
- X
- X/* Compare two files (or dirs) with specified names
- X DIR0/NAME0 and DIR1/NAME1, at level DEPTH in directory recursion.
- X (if DIR0 is 0, then the name is just NAME0, etc.)
- X This is self-contained; it opens the files and closes them.
- X
- X Value is 0 if files are identical, 1 if different,
- X 2 if there is a problem opening them. */
- X
- Xint
- Xcompare_files (dir0, name0, dir1, name1, depth)
- X char *dir0, *dir1;
- X char *name0, *name1;
- X int depth;
- X{
- X struct file_data inf[2];
- X register int i;
- X int val;
- X int errorcount = 0;
- X int stat_result[2];
- X
- X /* If this is directory comparison, perhaps we have a file
- X that exists only in one of the directories.
- X If so, just print a message to that effect. */
- X
- X if (! entire_new_file_flag && (name0 == 0 || name1 == 0))
- X {
- X char *name = name0 == 0 ? name1 : name0;
- X char *dir = name0 == 0 ? dir1 : dir0;
- X message ("Only in %s: %s\n", dir, name);
- X /* Return 1 so that diff_dirs will return 1 ("some files differ"). */
- X return 1;
- X }
- X
- X /* Mark any nonexistent file with -1 in the desc field. */
- X
- X inf[0].desc = name0 == 0 ? -1 : 0;
- X inf[1].desc = name1 == 0 ? -1 : 0;
- X
- X /* Now record the full name of each file, including nonexistent ones. */
- X
- X if (name0 == 0)
- X name0 = name1;
- X if (name1 == 0)
- X name1 = name0;
- X
- X inf[0].name = dir0 == 0 ? name0 : concat (dir0, "/", name0);
- X inf[1].name = dir1 == 0 ? name1 : concat (dir1, "/", name1);
- X
- X /* Stat the files. Record whether they are directories.
- X Record in stat_result whether stat fails. */
- X
- X for (i = 0; i <= 1; i++)
- X {
- X inf[i].stat.st_size = 0;
- X inf[i].stat.st_mtime = 0;
- X inf[i].dir_p = 0;
- X stat_result[i] = 0;
- X
- X if (inf[i].desc != -1
- X && strcmp (inf[i].name, "-"))
- X {
- X char *filename = inf[i].name;
- X
- X stat_result[i] = stat (filename, &inf[i].stat);
- X if (stat_result[i] < 0)
- X {
- X perror_with_name (filename);
- X errorcount = 1;
- X }
- X else
- X#ifdef AMIGA
- X inf[i].dir_p = (inf[i].stat.st_type > 0);
- X#else
- X inf[i].dir_p = (S_IFDIR == (inf[i].stat.st_mode & S_IFMT));
- X#endif
- X }
- X }
- X
- X /* See if the two named files are actually the same physical file.
- X If so, we know they are identical without actually reading them. */
- X
- X#ifndef AMIGA
- X if (inf[0].stat.st_ino == inf[1].stat.st_ino
- X && inf[0].stat.st_dev == inf[1].stat.st_dev
- X && stat_result[0] == 0
- X && stat_result[1] == 0)
- X {
- X val = 0;
- X goto done;
- X }
- X#endif
- X
- X if (name0 == 0)
- X inf[0].dir_p = inf[1].dir_p;
- X if (name1 == 0)
- X inf[1].dir_p = inf[0].dir_p;
- X
- X /* Open the files and record their descriptors. */
- X
- X for (i = 0; i <= 1; i++)
- X {
- X if (inf[i].desc == -1)
- X ;
- X else if (!strcmp (inf[i].name, "-"))
- X {
- X inf[i].desc = fileno(stdin);
- X inf[i].name = "Standard Input";
- X#ifdef AMIGA
- X inf[i].stat.st_type = -1;
- X#endif
- X }
- X /* Don't bother opening if stat already failed. */
- X else if (stat_result[i] == 0 && ! inf[i].dir_p)
- X {
- X char *filename = inf[i].name;
- X
- X inf[i].desc = open (filename, O_RDONLY, 0);
- X if (0 > inf[i].desc)
- X {
- X perror_with_name (filename);
- X errorcount = 1;
- X }
- X }
- X }
- X
- X if (errorcount)
- X {
- X
- X /* If either file should exist but fails to be opened, return 2. */
- X
- X val = 2;
- X
- X }
- X else if (inf[0].dir_p && inf[1].dir_p)
- X {
- X
- X /* If both are directories, compare the files in them. */
- X
- X if (depth > 0 && !recursive)
- X {
- X /* But don't compare dir contents one level down
- X unless -r was specified. */
- X message ("Common subdirectories: %s and %s\n",
- X inf[0].name, inf[1].name);
- X val = 0;
- X }
- X else
- X {
- X val = diff_dirs (inf[0].name, inf[1].name,
- X compare_files, depth, 0, 0);
- X }
- X
- X }
- X else if (depth == 0 && (inf[0].dir_p || inf[1].dir_p))
- X {
- X
- X /* If only one is a directory, and it was specified in the command line,
- X use the file in that dir whose basename matches the other file. */
- X
- X int dir_arg = (inf[0].dir_p ? 0 : 1);
- X int fnm_arg = (inf[0].dir_p ? 1 : 0);
- X char *p = strrchr(inf[fnm_arg].name, '/');
- X char *filename = concat (inf[dir_arg].name, "/",
- X (p ? p+1 : inf[fnm_arg].name));
- X
- X#ifdef AMIGA
- X inf[dir_arg].dir_p = (getfa(filename) == 1);
- X if (!inf[dir_arg].dir_p)
- X {
- X if (stat (filename,&inf[dir_arg].stat) < 0)
- X pfatal_with_name (filename);
- X inf[dir_arg].desc = open (filename, O_RDONLY, 0);
- X if (0 > inf[dir_arg].desc)
- X {
- X perror_with_name (filename);
- X val = 2;
- X }
- X/* free (inf[dir_arg].name); */
- X inf[dir_arg].name = filename;
- X val = diff_2_files (inf, depth);
- X }
- X else
- X {
- X error ("%s is a directory but %s is not",
- X inf[dir_arg].name, inf[fnm_arg].name);
- X val = 2;
- X }
- X#else
- X inf[dir_arg].desc = open (filename, O_RDONLY, 0);
- X
- X if (0 > inf[dir_arg].desc)
- X {
- X perror_with_name (filename);
- X val = 2;
- X }
- X else
- X {
- X /* JF: patch from the net to check and make sure we can really free
- X this. If it's from argv[], freeing it is a *really* bad idea */
- X if (0 != (dir_arg ? dir1 : dir0))
- X free (inf[dir_arg].name);
- X inf[dir_arg].name = filename;
- X if (fstat (inf[dir_arg].desc, &inf[dir_arg].stat) < 0)
- X pfatal_with_name (inf[dir_arg].name);
- X
- X inf[dir_arg].dir_p
- X = (S_IFDIR == (inf[dir_arg].stat.st_mode & S_IFMT));
- X if (inf[dir_arg].dir_p)
- X {
- X error ("%s is a directory but %s is not",
- X inf[dir_arg].name, inf[fnm_arg].name);
- X val = 1;
- X }
- X else
- X val = diff_2_files (inf, depth);
- X }
- X#endif
- X }
- X else if (depth > 0 && (inf[0].dir_p || inf[1].dir_p))
- X {
- X /* Perhaps we have a subdirectory that exists only in one directory.
- X If so, just print a message to that effect. */
- X
- X if (inf[0].desc == -1 || inf[1].desc == -1)
- X {
- X if (entire_new_file_flag && recursive)
- X val = diff_dirs (inf[0].name, inf[1].name, compare_files, depth,
- X inf[0].desc == -1, inf[1].desc == -1);
- X else
- X {
- X char *dir = (inf[0].desc == -1) ? dir1 : dir0;
- X message ("Only in %s: %s\n", dir, name0);
- X val = 1;
- X }
- X }
- X else
- X {
- X /* We have a subdirectory in one directory
- X and a file in the other. */
- X
- X if (inf[0].dir_p)
- X message ("%s is a directory but %s is not\n",
- X inf[0].name, inf[1].name);
- X else
- X message ("%s is a directory but %s is not\n",
- X inf[1].name, inf[0].name);
- X /* This is a difference. */
- X val = 1;
- X }
- X }
- X else
- X {
- X
- X /* Both exist and both are ordinary files. */
- X
- X val = diff_2_files (inf, depth);
- X
- X }
- X
- X /* Now the comparison has been done, if no error prevented it,
- X and VAL is the value this function will return. */
- X
- X if (inf[0].desc > 0)
- X close (inf[0].desc);
- X if (inf[1].desc > 0)
- X close (inf[1].desc);
- X
- X done:
- X if (val == 0 && print_file_same_flag && !inf[0].dir_p)
- X message ("Files %s and %s are identical\n",
- X inf[0].name, inf[1].name);
- X
- X fflush (stdout);
- X
- X if (dir0 != 0)
- X free (inf[0].name);
- X if (dir1 != 0)
- X free (inf[1].name);
- X
- X return val;
- X}
- SHAR_EOF
- echo "extracting diff/diff3.c"
- sed 's/^X//' << \SHAR_EOF > diff/diff3.c
- X/* Three-way file comparison program (diff3) for Project GNU
- X Copyright (C) 1988, 1989 Free Software Foundation, Inc.
- X
- X This program is free software; you can redistribute it and/or modify
- X it under the terms of the GNU General Public License as published by
- X the Free Software Foundation; either version 1, or (at your option)
- X any later version.
- X
- X This program is distributed in the hope that it will be useful,
- X but WITHOUT ANY WARRANTY; without even the implied warranty of
- X MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- X GNU General Public License for more details.
- X
- X You should have received a copy of the GNU General Public License
- X along with this program; if not, write to the Free Software
- X Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
- X
- X
- X/* Written by Randy Smith */
- X
- X/*
- X * Include files.
- X */
- X#include <stdio.h>
- X#include <ctype.h>
- X
- X#if defined(USG) || defined(AMIGA)
- X/* Define needed BSD functions in terms of sysV library. */
- X
- X#define bcopy(s,d,n) memcpy((d),(s),(n))
- X#define bcmp(s1,s2,n) memcmp((s1),(s2),(n))
- X#define bzero(s,n) memset((s),0,(n))
- X#endif
- X
- X#ifdef USG
- X#define dup2(f,t) (close(t),fcntl((f),F_DUPFD,(t)))
- X
- X#define vfork fork
- X#define index strchr
- X#define rindex strrchr
- X#endif
- X/*
- X * Internal data structures and macros for the diff3 program; includes
- X * data structures for both diff3 diffs and normal diffs.
- X */
- X
- X/*
- X * Different files within a diff
- X */
- X#define FILE0 0
- X#define FILE1 1
- X#define FILE2 2
- X
- X/*
- X * Three way diffs are build out of two two-way diffs; the file which
- X * the two two-way diffs share is:
- X */
- X#define FILEC FILE0
- X
- X/* The ranges are indexed by */
- X#define START 0
- X#define END 1
- X
- Xenum diff_type {
- X ERROR, /* Should not be used */
- X ADD, /* Two way diff add */
- X CHANGE, /* Two way diff change */
- X DELETE, /* Two way diff delete */
- X DIFF_ALL, /* All three are different */
- X DIFF_1ST, /* Only the first is different */
- X DIFF_2ND, /* Only the second */
- X DIFF_3RD /* Only the third */
- X};
- X
- X/* Two-way diff */
- Xstruct diff_block {
- X int ranges[2][2]; /* Ranges are inclusive */
- X char **lines[2]; /* The actual lines (may contain nulls) */
- X int *lengths[2]; /* The lengths of the lines (since nulls) */
- X struct diff_block *next;
- X};
- X
- X/* Three-way diff */
- X
- Xstruct diff3_block {
- X enum diff_type correspond; /* Type of diff */
- X int ranges[3][2]; /* Ranges are inclusive */
- X char **lines[3]; /* The actual lines (may contain nulls) */
- X int *lengths[3]; /* The lengths of the lines (since nulls) */
- X struct diff3_block *next;
- X};
- X
- X/*
- X * Access the ranges on a diff block.
- X */
- X#define D_LOWLINE(diff, filenum) \
- X ((diff)->ranges[filenum][START])
- X#define D_HIGHLINE(diff, filenum) \
- X ((diff)->ranges[filenum][END])
- X#define D_NUMLINES(diff, filenum) \
- X (D_HIGHLINE((diff), (filenum)) - D_LOWLINE((diff), (filenum)) + 1)
- X
- X/*
- X * Access the line numbers in a file in a diff by absolute line number
- X * (i.e. line number within the original file). Note that these are
- X * lvalues and can be used for assignment.
- X */
- X#define D_LINENUM(diff, filenum, linenum) \
- X (*((diff)->lines[filenum] + linenum - D_LOWLINE((diff), (filenum))))
- X#define D_LINELEN(diff, filenum, linenum) \
- X (*((diff)->lengths[filenum] + linenum - D_LOWLINE((diff), (filenum))))
- X
- X/*
- X * Access the line numbers in a file in a diff by relative line
- X * numbers (i.e. line number within the diff itself). Note that these
- X * are lvalues and can be used for assignment.
- X */
- X#define D_RELNUM(diff, filenum, linenum) \
- X (*((diff)->lines[filenum] + linenum))
- X#define D_RELLEN(diff, filenum, linenum) \
- X (*((diff)->lengths[filenum] + linenum))
- X
- X/*
- X * And get at them directly, when that should be necessary.
- X */
- X#define D_LINEARRAY(diff, filenum) \
- X ((diff)->lines[filenum])
- X#define D_LENARRAY(diff, filenum) \
- X ((diff)->lengths[filenum])
- X
- X/*
- X * Next block.
- X */
- X#define D_NEXT(diff) ((diff)->next)
- X
- X/*
- X * Access the type of a diff3 block.
- X */
- X#define D3_TYPE(diff) ((diff)->correspond)
- X
- X/*
- X * Line mappings based on diffs. The first maps off the top of the
- X * diff, the second off of the bottom.
- X */
- X#define D_HIGH_MAPLINE(diff, fromfile, tofile, lineno) \
- X ((lineno) \
- X - D_HIGHLINE ((diff), (fromfile)) \
- X + D_HIGHLINE ((diff), (tofile)))
- X
- X#define D_LOW_MAPLINE(diff, fromfile, tofile, lineno) \
- X ((lineno) \
- X - D_LOWLINE ((diff), (fromfile)) \
- X + D_LOWLINE ((diff), (tofile)))
- X
- X/*
- X * General memory allocation function.
- X */
- X#define ALLOCATE(number, type) \
- X (type *) xmalloc ((number) * sizeof (type))
- X
- X/*
- X * Options variables for flags set on command line.
- X *
- X * EDSCRIPT: Write out an ed script instead of the standard diff3 format.
- X *
- X * FLAGGING: Indicates that in the case of overlapping diffs (type
- X * DIFF_ALL), the lines which would normally be deleted from file 1
- X * should be preserved with a special flagging mechanism.
- X *
- X * DONT_WRITE_OVERLAP: 1 if information for overlapping diffs should
- X * not be output.
- X *
- X * DONT_WRITE_SIMPLE: 1 if information for non-overlapping diffs
- X * should not be output.
- X *
- X * FINALWRITE: 1 if a :wq should be included at the end of the script
- X * to write out the file being edited.
- X */
- X#define DIFF_PROGRAM "rcs:diff"
- X
- Xint edscript;
- Xint flagging;
- Xint dont_write_overlap;
- Xint dont_write_simple;
- Xint finalwrite;
- Xint overlaps;
- Xextern int optind;
- X
- Xchar *argv0;
- X
- X/*
- X * Forward function declarations.
- X */
- Xstruct diff_block *process_diff ();
- Xstruct diff3_block *make_3way_diff ();
- Xvoid output_diff3 ();
- Xvoid output_diff3_edscript ();
- Xvoid usage ();
- Xvoid fatal ();
- Xvoid perror_with_exit ();
- X
- Xstruct diff3_block *using_to_diff3_block ();
- Xint copy_stringlist ();
- Xstruct diff3_block *create_diff3_block ();
- Xint compare_line_list ();
- X
- Xint read_diff ();
- Xenum diff_type process_diff_control ();
- Xchar *scan_diff_line ();
- X
- Xstruct diff3_block *reverse_diff3_blocklist ();
- X
- Xvoid *xmalloc ();
- Xvoid *xrealloc ();
- X
- X/*
- X * No options take arguments. "i" is my own addition; it stands for
- X * "include write command", to emulate system V behavior.
- X */
- X#define ARGSTRING "eix3EX"
- X
- Xchar diff_program[] = DIFF_PROGRAM;
- X
- X/*
- X * Main program. Calls diff twice on two pairs of input files,
- X * combines the two diffs, and outputs them.
- X */
- Xmain (argc, argv)
- X int argc;
- X char **argv;
- X{
- X int c;
- X int mapping [3];
- X int shiftmap;
- X int incompat;
- X struct diff_block *thread1, *thread2;
- X struct diff3_block *diff;
- X
- X edscript = flagging = dont_write_overlap
- X = dont_write_simple = finalwrite = 0;
- X incompat = shiftmap = 0;
- X
- X argv0 = argv[0];
- X
- X while ((c = getopt (argc, argv, ARGSTRING)) != EOF)
- X {
- X edscript = 1;
- X switch (c)
- X {
- X case 'x':
- X dont_write_simple = 1;
- X incompat++;
- X break;
- X case '3':
- X dont_write_overlap = 1;
- X incompat++;
- X break;
- X case 'i':
- X finalwrite = 1;
- X incompat++;
- X break;
- X case 'X':
- X dont_write_simple = 1;
- X /* Falls through */
- X case 'E':
- X flagging = 1;
- X /* Falls through */
- X case 'e':
- X incompat++;
- X break;
- X case '?':
- X default:
- X usage ();
- X /* NOTREACHED */
- X }
- X }
- X
- X if (incompat > 1) /* Make sure you only have one of a */
- X /* set of arguments */
- X usage ();
- X
- X if (argc - optind != 3)
- X usage ();
- X
- X if (*argv[optind] == '-' && *(argv[optind] + 1) == '\0')
- X {
- X /* Sigh. We've got standard input as the first arg. We can't */
- X /* call diff twice on stdin */
- X mapping [0] = 1;
- X mapping [1] = 2;
- X mapping [2] = 0;
- X shiftmap = 1;
- X }
- X else
- X {
- X /* Normal, what you'd expect */
- X mapping [0] = 0;
- X mapping [1] = 1;
- X mapping [2] = 2;
- X shiftmap = 0;
- X }
- X
- X if (shiftmap)
- X {
- X thread1 = process_diff (argv[optind + 2], argv[optind]);
- X thread2 = process_diff (argv[optind + 2], argv[optind + 1]);
- X }
- X else
- X {
- X thread1 = process_diff (argv[optind], argv[optind + 1]);
- X thread2 = process_diff (argv[optind], argv[optind + 2]);
- X }
- X diff = make_3way_diff (thread1, thread2);
- X if (edscript)
- X output_diff3_edscript (stdout, diff, mapping, argv[optind],
- X argv[optind + 1], argv[optind + 2]);
- X else
- X output_diff3 (stdout, diff, mapping);
- X exit (overlaps);
- X}
- X
- X/*
- X * Explain, patiently and kindly, how to use this program. Then exit.
- X */
- Xvoid
- Xusage ()
- X{
- X fprintf (stderr, "Usage:\t%s [ -exEX3 ] [ -i ] file1 file2 file3\n",
- X argv0);
- X fprintf (stderr, "\tOnly one of [exEX3] allowed\n");
- X exit (1);
- X}
- X
- X/*
- X * Routines that combine the two diffs together into one. The
- X * algorithm used follows:
- X *
- X * File0 is shared in common between the two diffs.
- X * Diff01 is the diff between 0 and 1.
- X * Diff02 is the diff between 0 and 2.
- X *
- X * 1) Find the range for the first block in File0.
- X * a) Take the lowest of the two ranges (in File0) in the two
- X * current blocks (one from each diff) as being the low
- X * water mark. Assign the upper end of this block as
- X * being the high water mark and move the current block up
- X * one. Mark the block just moved over as to be used.
- X * b) Check the next block in the diff that the high water
- X * mark is *not* from.
- X *
- X * *If* the high water mark is above
- X * the low end of the range in that block,
- X *
- X * mark that block as to be used and move the current
- X * block up. Set the high water mark to the max of
- X * the high end of this block and the current. Repeat b.
- X *
- X * 2) Find the corresponding ranges in Files1 (from the blocks
- X * in diff01; line per line outside of diffs) and in File2.
- X * Create a diff3_block, reserving space as indicated by the ranges.
- X *
- X * 3) Copy all of the pointers for file0 in. At least for now,
- X * do bcmp's between corresponding strings in the two diffs.
- X *
- X * 4) Copy all of the pointers for file1 and 2 in. Get what you
- X * need from file0 (when there isn't a diff block, it's
- X * identical to file0 within the range between diff blocks).
- X *
- X * 5) If the diff blocks you used came from only one of the two
- X * strings of diffs, then that file (i.e. the one other than
- X * file 0 in that diff) is the odd person out. If you used
- X * diff blocks from both sets, check to see if files 1 and 2 match:
- X *
- X * Same number of lines? If so, do a set of bcmp's (if a
- X * bcmp matches; copy the pointer over; it'll be easier later
- X * if you have to do any compares). If they match, 1 & 2 are
- X * the same. If not, all three different.
- X *
- X * Then you do it again, until you run out of blocks.
- X *
- X */
- X
- X/*
- X * This routine makes a three way diff (chain of diff3_block's) from two
- X * two way diffs (chains of diff_block's). It is assumed that each of
- X * the two diffs passed are off of the same file (i.e. that each of the
- X * diffs were made "from" the same file). The three way diff pointer
- X * returned will have numbering 0--the common file, 1--the other file
- X * in diff1, and 2--the other file in diff2.
- X */
- Xstruct diff3_block *
- Xmake_3way_diff (thread1, thread2)
- X struct diff_block *thread1, *thread2;
- X{
- X/*
- X * This routine works on the two diffs passed to it as threads.
- X * Thread number 0 is diff1, thread number 1 is diff2. The USING
- X * array is set to the base of the list of blocks to be used to
- X * construct each block of the three way diff; if no blocks from a
- X * particular thread are to be used, that element of the using array
- X * is set to 0. The elements LAST_USING array are set to the last
- X * elements on each of the using lists.
- X *
- X * The HIGH_WATER_MARK is set to the highest line number in File 0
- X * described in any of the diffs in either of the USING lists. The
- X * HIGH_WATER_THREAD names the thread. Similarly the BASE_WATER_MARK
- X * and BASE_WATER_THREAD describe the lowest line number in File 0
- X * described in any of the diffs in either of the USING lists. The
- X * HIGH_WATER_DIFF is the diff from which the HIGH_WATER_MARK was
- X * taken.
- X *
- X * The HIGH_WATER_DIFF should always be equal to LAST_USING
- X * [HIGH_WATER_THREAD]. The OTHER_DIFF is the next diff to check for
- X * higher water, and should always be equal to
- X * CURRENT[HIGH_WATER_THREAD ^ 0x1]. The OTHER_THREAD is the thread
- X * in which the OTHER_DIFF is, and hence should always be equal to
- X * HIGH_WATER_THREAD ^ 0x1.
- X *
- X * The variable LAST_DIFF is kept set to the last diff block produced
- X * by this routine, for line correspondence purposes between that diff
- X * and the one currently being worked on. It is initialized to
- X * ZERO_DIFF before any blocks have been created.
- X */
- X
- X struct diff_block
- X *using[2],
- X *last_using[2],
- X *current[2];
- X
- X int
- X high_water_mark,
- X base_water_mark;
- X
- X int
- X high_water_thread,
- X base_water_thread,
- X other_thread;
- X
- X struct diff_block
- X *high_water_diff,
- X *other_diff;
- X
- X struct diff3_block
- X *result,
- X *tmpblock,
- X *result_last,
- X *last_diff;
- X
- X static struct diff3_block zero_diff = {
- X ERROR,
- X { {0, 0}, {0, 0}, {0, 0} },
- X { (char **) 0, (char **) 0, (char **) 0 },
- X { (int *) 0, (int *) 0, (int *) 0 },
- X (struct diff3_block *) 0
- X };
- X
- X /* Initialization */
- X result = result_last = (struct diff3_block *) 0;
- X current[0] = thread1; current[1] = thread2;
- X last_diff = &zero_diff;
- X
- X /* Sniff up the threads until we reach the end */
- X
- X while (current[0] || current[1])
- X {
- X using[0] = using[1] = last_using[0] = last_using[1] =
- X (struct diff_block *) 0;
- X
- X /* Setup low and high water threads, diffs, and marks */
- X if (!current[0])
- X base_water_thread = 1;
- X else if (!current[1])
- X base_water_thread = 0;
- X else
- X base_water_thread =
- X (D_LOWLINE (current[0], FILE0)
- X > D_LOWLINE (current[1], FILE0));
- X high_water_thread = base_water_thread;
- X
- X high_water_diff = current[high_water_thread];
- X
- X /* low and high waters start off same diff */
- X base_water_mark = D_LOWLINE (high_water_diff, FILE0);
- X
- X high_water_mark = D_HIGHLINE (high_water_diff, FILE0);
- X
- X /* Make the diff you just got info from into the using class */
- X using[high_water_thread]
- X = last_using[high_water_thread]
- X = high_water_diff;
- X current[high_water_thread] = high_water_diff->next;
- X last_using[high_water_thread]->next
- X = (struct diff_block *) 0;
- X
- X /* And mark the other diff */
- X other_thread = high_water_thread ^ 0x1;
- X other_diff = current[other_thread];
- X
- X /* Shuffle up the ladder, checking the other diff to see if it
- X needs to be incorporated */
- X while (other_diff
- X && D_LOWLINE (other_diff, FILE0) <= high_water_mark + 1)
- X {
- X
- X /* Incorporate this diff into the using list. Note that
- X this doesn't take it off the current list */
- X if (using[other_thread])
- X last_using[other_thread]->next = other_diff;
- X else
- X using[other_thread] = other_diff;
- X last_using[other_thread] = other_diff;
- X
- X /* Take it off the current list. Note that this following
- X code assumes that other_diff enters it equal to
- X current[high_water_thread ^ 0x1] */
- X current[other_thread]
- X = current[other_thread]->next;
- X other_diff->next
- X = (struct diff_block *) 0;
- X
- X /* Set the high_water stuff
- X If this comparison is equal, then this is the last pass
- X through this loop; since diff blocks within a given
- X thread cannot overlap, the high_water_mark will be
- X *below* the range_start of either of the next diffs. */
- X
- X if (high_water_mark < D_HIGHLINE (other_diff, FILE0))
- X {
- X high_water_thread ^= 1;
- X high_water_diff = other_diff;
- X high_water_mark = D_HIGHLINE (other_diff, FILE0);
- X }
- X
- X /* Set the other diff */
- X other_thread = high_water_thread ^ 0x1;
- X other_diff = current[other_thread];
- X }
- X
- X /* The using lists contain a list of all of the blocks to be
- X included in this diff3_block. Create it. */
- X
- X tmpblock = using_to_diff3_block (using, last_using,
- X base_water_thread, high_water_thread,
- X last_diff);
- X
- X if (!tmpblock)
- X fatal ("internal: screwup in format of diff blocks");
- X
- X /* Put it on the list */
- X if (result)
- X result_last->next = tmpblock;
- X else
- X result = tmpblock;
- X result_last = tmpblock;
- X
- X /* Setup corresponding lines correctly */
- X last_diff = tmpblock;
- X }
- X return result;
- X}
- X
- X/*
- X * using_to_diff3_block:
- X * This routine takes two lists of blocks (from two separate diff
- X * threads) and puts them together into one diff3 block.
- X * It then returns a pointer to this diff3 block or 0 for failure.
- X *
- X * All arguments besides using are for the convenience of the routine;
- X * they could be derived from the using array.
- X * LAST_USING is a pair of pointers to the last blocks in the using
- X * structure.
- X * LOW_THREAD and HIGH_THREAD tell which threads contain the lowest
- X * and highest line numbers for File0.
- X * last_diff contains the last diff produced in the calling routine.
- X * This is used for lines mappings which would still be identical to
- X * the state that diff ended in.
- X *
- X * A distinction should be made in this routine between the two diffs
- X * that are part of a normal two diff block, and the three diffs that
- X * are part of a diff3_block.
- X */
- Xstruct diff3_block *
- Xusing_to_diff3_block (using, last_using, low_thread, high_thread, last_diff)
- X struct diff_block
- X *using[2],
- X *last_using[2];
- X int low_thread, high_thread;
- X struct diff3_block *last_diff;
- X{
- X int lowc, highc, low1, high1, low2, high2;
- X struct diff3_block *result;
- X struct diff_block *ptr;
- X int i;
- X int current0line;
- X
- X /* Find the range in file0 */
- X lowc = using[low_thread]->ranges[0][START];
- X highc = last_using[high_thread]->ranges[0][END];
- X
- X /* Find the ranges in the other files.
- X If using[x] is null, that means that the file to which that diff
- X refers is equivalent to file 0 over this range */
- X
- X if (using[0])
- X {
- X low1 = D_LOW_MAPLINE (using[0], FILE0, FILE1, lowc);
- X high1 = D_HIGH_MAPLINE (last_using[0], FILE0, FILE1, highc);
- X }
- X else
- X {
- X low1 = D_HIGH_MAPLINE (last_diff, FILEC, FILE1, lowc);
- X high1 = D_HIGH_MAPLINE (last_diff, FILEC, FILE1, highc);
- X }
- X
- X /*
- X * Note that in the following, we use file 1 relative to the diff,
- X * and file 2 relative to the corresponding lines struct.
- X */
- X if (using[1])
- X {
- X low2 = D_LOW_MAPLINE (using[1], FILE0, FILE1, lowc);
- X high2 = D_HIGH_MAPLINE (last_using[1], FILE0, FILE1, highc);
- X }
- X else
- X {
- X low2 = D_HIGH_MAPLINE (last_diff, FILEC, FILE2, lowc);
- X high2 = D_HIGH_MAPLINE (last_diff, FILEC, FILE2, highc);
- X }
- X
- X /* Create a block with the appropriate sizes */
- X result = create_diff3_block (lowc, highc, low1, high1, low2, high2);
- X
- X /* Copy over all of the information for File 0. Return with a zero
- X if any of the compares failed. */
- X for (ptr = using[0]; ptr; ptr = D_NEXT (ptr))
- X {
- X int result_offset = D_LOWLINE (ptr, FILE0) - lowc;
- X int copy_size
- X = D_HIGHLINE (ptr, FILE0) - D_LOWLINE (ptr, FILE0) + 1;
- X
- X if (!copy_stringlist (D_LINEARRAY (ptr, FILE0),
- X D_LENARRAY (ptr, FILE0),
- X D_LINEARRAY (result, FILEC) + result_offset,
- X D_LENARRAY (result, FILEC) + result_offset,
- X copy_size))
- X return 0;
- X }
- X
- X for (ptr = using[1]; ptr; ptr = D_NEXT (ptr))
- X {
- X int result_offset = D_LOWLINE (ptr, FILEC) - lowc;
- X int copy_size
- X = D_HIGHLINE (ptr, FILEC) - D_LOWLINE (ptr, FILEC) + 1;
- X
- X if (!copy_stringlist (D_LINEARRAY (ptr, FILE0),
- X D_LENARRAY (ptr, FILE0),
- X D_LINEARRAY (result, FILEC) + result_offset,
- X D_LENARRAY (result, FILEC) + result_offset,
- X copy_size))
- X return 0;
- X }
- X
- X /* Copy stuff for file 1. First deal with anything that might be
- X before the first diff. */
- X
- X for (i = 0;
- X i + low1 < (using[0] ? D_LOWLINE (using[0], FILE1) : high1 + 1);
- X i++)
- X {
- X D_RELNUM (result, FILE1, i) = D_RELNUM (result, FILEC, i);
- X D_RELLEN (result, FILE1, i) = D_RELLEN (result, FILEC, i);
- X }
- X
- X for (ptr = using[0]; ptr; ptr = D_NEXT (ptr))
- X {
- X int result_offset = D_LOWLINE (ptr, FILE1) - low1;
- X int copy_size
- X = D_HIGHLINE (ptr, FILE1) - D_LOWLINE (ptr, FILE1) + 1;
- X
- X if (!copy_stringlist (D_LINEARRAY (ptr, FILE1),
- X D_LENARRAY (ptr, FILE1),
- X D_LINEARRAY (result, FILE1) + result_offset,
- X D_LENARRAY (result, FILE1) + result_offset,
- X copy_size))
- X return 0;
- X
- X /* Catch the lines between here and the next diff */
- X current0line = D_HIGHLINE (ptr, FILE0) + 1 - lowc;
- X for (i = D_HIGHLINE (ptr, FILE1) + 1 - low1;
- X i < (D_NEXT (ptr) ?
- X D_LOWLINE (D_NEXT (ptr), FILE1) :
- X high1 + 1) - low1;
- X i++)
- X {
- X D_RELNUM (result, FILE1, i)
- X = D_RELNUM (result, FILEC, current0line);
- X D_RELLEN (result, FILE1, i)
- X = D_RELLEN (result, FILEC, current0line++);
- X }
- X }
- X
- X /* Copy stuff for file 2. First deal with anything that might be
- X before the first diff. */
- X
- X for (i = 0;
- X i + low2 < (using[1] ? D_LOWLINE (using[1], FILE1) : high2 + 1);
- X i++)
- X {
- X D_RELNUM (result, FILE2, i) = D_RELNUM (result, FILEC, i);
- X D_RELLEN (result, FILE2, i) = D_RELLEN (result, FILEC, i);
- X }
- X
- X for (ptr = using[1]; ptr; ptr = D_NEXT (ptr))
- X {
- X int result_offset = D_LOWLINE (ptr, FILE1) - low2;
- X int copy_size
- X = D_HIGHLINE (ptr, FILE1) - D_LOWLINE (ptr, FILE1) + 1;
- X
- X if (!copy_stringlist (D_LINEARRAY (ptr, FILE1),
- X D_LENARRAY (ptr, FILE1),
- X D_LINEARRAY (result, FILE2) + result_offset,
- X D_LENARRAY (result, FILE2) + result_offset,
- X copy_size))
- X return 0;
- X
- X /* Catch the lines between here and the next diff */
- X current0line = D_HIGHLINE (ptr, FILE0) + 1 - lowc;
- X for (i = D_HIGHLINE (ptr, FILE1) + 1 - low2;
- X i < (D_NEXT (ptr) ?
- X D_LOWLINE (D_NEXT (ptr), FILE1) :
- X high2 + 1) - low2;
- X i++)
- X {
- X D_RELNUM (result, FILE2, i)
- X = D_RELNUM (result, FILEC, current0line);
- X D_RELLEN (result, FILE2, i)
- X = D_RELLEN (result, FILEC, current0line++);
- X }
- X }
- X
- X /* Set correspond */
- X if (!using[0])
- X D3_TYPE (result) = DIFF_3RD;
- X else if (!using[1])
- X D3_TYPE (result) = DIFF_2ND;
- X else
- X {
- X int nl1
- X = D_HIGHLINE (result, FILE1) - D_LOWLINE (result, FILE1) + 1;
- X int nl2
- X = D_HIGHLINE (result, FILE2) - D_LOWLINE (result, FILE2) + 1;
- X
- X if (nl1 != nl2
- X || !compare_line_list (D_LINEARRAY (result, FILE1),
- X D_LENARRAY (result, FILE1),
- X D_LINEARRAY (result, FILE2),
- X D_LENARRAY (result, FILE2),
- X nl1))
- X D3_TYPE (result) = DIFF_ALL;
- X else
- X D3_TYPE (result) = DIFF_1ST;
- X }
- X
- X return result;
- X}
- X
- X/*
- X * This routine copies pointers from a list of strings to a different list
- X * of strings. If a spot in the second list is already filled, it
- X * makes sure that it is filled with the same string; if not it
- X * returns 0, the copy incomplete.
- X * Upon successful completion of the copy, it returns 1.
- X */
- Xint
- Xcopy_stringlist (fromptrs, fromlengths, toptrs, tolengths, copynum)
- X char *fromptrs[], *toptrs[];
- X int *fromlengths, *tolengths;
- X int copynum;
- X{
- X register char
- X **f = fromptrs,
- X **t = toptrs;
- X register int
- X *fl = fromlengths,
- X *tl = tolengths;
- X
- X while (copynum--)
- X {
- X if (*t)
- X {
- X if (*fl != *tl || bcmp (*f, *t, *fl))
- X return 0;
- X }
- X else
- X { *t = *f ; *tl = *fl; }
- X
- X t++; f++; tl++; fl++;
- X }
- X return 1;
- X}
- X
- X/*
- X * Create a diff3_block, with ranges as specified in the arguments.
- X * Allocate the arrays for the various pointers (and zero them) based
- X * on the arguments passed. Return the block as a result.
- X */
- Xstruct diff3_block *
- Xcreate_diff3_block (low0, high0, low1, high1, low2, high2)
- X register int low0, high0, low1, high1, low2, high2;
- X{
- X struct diff3_block *result = ALLOCATE (1, struct diff3_block);
- X int numlines;
- X
- X D3_TYPE (result) = ERROR;
- X
- X /* Assign ranges */
- X D_LOWLINE (result, FILE0) = low0;
- X D_HIGHLINE (result, FILE0) = high0;
- X D_LOWLINE (result, FILE1) = low1;
- X D_HIGHLINE (result, FILE1) = high1;
- X D_LOWLINE (result, FILE2) = low2;
- X D_HIGHLINE (result, FILE2) = high2;
- X
- X /* Allocate and zero space */
- X numlines = D_NUMLINES (result, FILE0);
- X if (numlines)
- X {
- X D_LINEARRAY (result, FILE0) = ALLOCATE (numlines, char *);
- X D_LENARRAY (result, FILE0) = ALLOCATE (numlines, int);
- X bzero (D_LINEARRAY (result, FILE0), (numlines * sizeof (char *)));
- X bzero (D_LENARRAY (result, FILE0), (numlines * sizeof (int)));
- X }
- X else
- X {
- X D_LINEARRAY (result, FILE0) = (char **) 0;
- X D_LENARRAY (result, FILE0) = (int *) 0;
- X }
- X
- X numlines = D_NUMLINES (result, FILE1);
- X if (numlines)
- X {
- X D_LINEARRAY (result, FILE1) = ALLOCATE (numlines, char *);
- X D_LENARRAY (result, FILE1) = ALLOCATE (numlines, int);
- X bzero (D_LINEARRAY (result, FILE1), (numlines * sizeof (char *)));
- X bzero (D_LENARRAY (result, FILE1), (numlines * sizeof (int)));
- X }
- X else
- X {
- X D_LINEARRAY (result, FILE1) = (char **) 0;
- X D_LENARRAY (result, FILE1) = (int *) 0;
- X }
- X
- X numlines = D_NUMLINES (result, FILE2);
- X if (numlines)
- X {
- X D_LINEARRAY (result, FILE2) = ALLOCATE (numlines, char *);
- X D_LENARRAY (result, FILE2) = ALLOCATE (numlines, int);
- X bzero (D_LINEARRAY (result, FILE2), (numlines * sizeof (char *)));
- X bzero (D_LENARRAY (result, FILE2), (numlines * sizeof (int)));
- X }
- X else
- X {
- X D_LINEARRAY (result, FILE2) = (char **) 0;
- X D_LENARRAY (result, FILE2) = (int *) 0;
- X }
- X
- X /* Return */
- X return result;
- X}
- X
- X/*
- X * Compare two lists of lines of text.
- X * Return 1 if they are equivalent, 0 if not.
- X */
- Xint
- Xcompare_line_list (list1, lengths1, list2, lengths2, nl)
- X char *list1[], *list2[];
- X int *lengths1, *lengths2;
- X int nl;
- X{
- X char
- X **l1 = list1,
- X **l2 = list2;
- X int
- X *lgths1 = lengths1,
- X *lgths2 = lengths2;
- X
- X while (nl--)
- X if (!*l1 || !*l2 || *lgths1 != *lgths2++
- X || bcmp (*l1++, *l2++, *lgths1++))
- X return 0;
- X return 1;
- X}
- X
- X/*
- X * Routines to input and parse two way diffs.
- X */
- X
- Xextern char *environ; /* I hope this is here */
- X
- X#define DIFF_CHUNK_SIZE 10000
- X
- Xstruct diff_block *
- Xprocess_diff (filea, fileb)
- X char *filea, *fileb;
- X{
- X char *diff_contents;
- X int diff_size;
- X char *scan_diff;
- X enum diff_type dt;
- X int i;
- X struct diff_block *block_list, *block_list_end, *bptr;
- X
- X diff_size = read_diff (filea, fileb, &diff_contents);
- X scan_diff = diff_contents;
- X bptr = block_list_end = block_list = (struct diff_block *) 0;
- X
- X while (scan_diff - diff_contents < diff_size)
- X {
- X bptr = ALLOCATE (1, struct diff_block);
- X bptr->lines[0] = bptr->lines[1] = (char **) 0;
- X bptr->lengths[0] = bptr->lengths[1] = (int *) 0;
- X
- X dt = process_diff_control (&scan_diff, bptr);
- X if (dt == ERROR) fatal ("Bad format in diff output");
- X if (*scan_diff != '\n') fatal ("Bad format in diff output");
- X scan_diff++;
- X
- X /* Force appropriate ranges to be null, if necessary */
- X switch (dt)
- X {
- X case ADD:
- X bptr->ranges[0][0]++;
- X break;
- X case DELETE:
- X bptr->ranges[1][0]++;
- X break;
- X case CHANGE:
- X break;
- X default:
- X fatal ("internal: Bad diff type in process_diff");
- X break;
- X }
- X
- X /* Allocate space for the pointers for the lines from filea, and
- X parcel them out among these pointers */
- X if (dt != ADD)
- X {
- X bptr->lines[0] = ALLOCATE ((bptr->ranges[0][END]
- X - bptr->ranges[0][START] + 1),
- X char *);
- X bptr->lengths[0] = ALLOCATE ((bptr->ranges[0][END]
- X - bptr->ranges[0][START] + 1),
- X int);
- X for (i = 0; i <= (bptr->ranges[0][END]
- X - bptr->ranges[0][START]); i++)
- X scan_diff = scan_diff_line (scan_diff,
- X &(bptr->lines[0][i]),
- X &(bptr->lengths[0][i]),
- X diff_contents + diff_size,
- X '<');
- X }
- X
- X /* Get past the separator for changes */
- X if (dt == CHANGE)
- X {
- X if (strncmp (scan_diff, "---\n", 4))
- X fatal ("Bad diff format: bad change separator");
- X scan_diff += 4;
- X }
- X
- X /* Allocate space for the pointers for the lines from fileb, and
- X parcel them out among these pointers */
- X if (dt != DELETE)
- X {
- X bptr->lines[1] = ALLOCATE ((bptr->ranges[1][END]
- X - bptr->ranges[1][START] + 1),
- X char *);
- X bptr->lengths[1] = ALLOCATE ((bptr->ranges[1][END]
- X - bptr->ranges[1][START] + 1),
- X int);
- X for (i = 0; i <= (bptr->ranges[1][END]
- X - bptr->ranges[1][START]); i++)
- X scan_diff = scan_diff_line (scan_diff,
- X &(bptr->lines[1][i]),
- X &(bptr->lengths[1][i]),
- X diff_contents + diff_size,
- X '>');
- X }
- X
- X /* Place this block on the blocklist */
- X if (block_list_end)
- X block_list_end->next = bptr;
- X else
- X block_list = bptr;
- X
- X block_list_end = bptr;
- X
- X }
- X
- X if (scan_diff - diff_contents != diff_size)
- X fatal ("bad diff format; incomplete last line");
- X
- X return block_list;
- X}
- X
- X/*
- X * This routine will parse a normal format diff control string. It
- X * returns the type of the diff (ERROR if the format is bad). All of
- X * the other important information is filled into to the structure
- X * pointed to by db, and the string pointer (whose location is passed
- X * to this routine) is updated to point beyond the end of the string
- X * parsed. Note that only the ranges in the diff_block will be set by
- X * this routine.
- X *
- X * If some specific pair of numbers has been reduced to a single
- X * number, then both corresponding numbers in the diff block are set
- X * to that number. In general these numbers are interpetted as ranges
- X * inclusive, unless being used by the ADD or DELETE commands. It is
- X * assumed that these will be special cased in a superior routine.
- X */
- X
- Xenum diff_type
- Xprocess_diff_control (string, db)
- X char **string;
- X struct diff_block *db;
- X{
- X char *s = *string;
- X int holdnum;
- X enum diff_type type;
- X
- X/* These macros are defined here because they can use variables
- X defined in this function. Don't try this at home kids, we're
- X trained professionals!
- X
- X Also note that SKIPWHITE only recognizes tabs and spaces, and
- X that READNUM can only read positive, integral numbers */
- X
- X#define SKIPWHITE(s) { while (*s == ' ' || *s == '\t') s++; }
- X#define READNUM(s, num) \
- X { if (!isdigit (*s)) return ERROR; holdnum = 0; \
- X do { holdnum = (*s++ - '0' + holdnum * 10); } \
- X while (isdigit (*s)); (num) = holdnum; }
- X
- X /* Read first set of digits */
- X SKIPWHITE (s);
- X READNUM (s, db->ranges[0][START]);
- X
- X /* Was that the only digit? */
- X SKIPWHITE(s);
- X if (*s == ',')
- X {
- X /* Get the next digit */
- X s++;
- X READNUM (s, db->ranges[0][END]);
- X }
- X else
- X db->ranges[0][END] = db->ranges[0][START];
- X
- X /* Get the letter */
- X SKIPWHITE (s);
- X switch (*s)
- X {
- X case 'a':
- X type = ADD;
- X break;
- X case 'c':
- X type = CHANGE;
- X break;
- X case 'd':
- X type = DELETE;
- X break;
- X default:
- X return ERROR; /* Bad format */
- X }
- X s++; /* Past letter */
- X
- X /* Read second set of digits */
- X SKIPWHITE (s);
- X READNUM (s, db->ranges[1][START]);
- X
- X /* Was that the only digit? */
- X SKIPWHITE(s);
- X if (*s == ',')
- X {
- X /* Get the next digit */
- X s++;
- X READNUM (s, db->ranges[1][END]);
- X SKIPWHITE (s); /* To move to end */
- X }
- X else
- X db->ranges[1][END] = db->ranges[1][START];
- X
- X *string = s;
- X return type;
- X}
- X
- Xint
- Xread_diff (filea, fileb, output_placement)
- X char *filea, *fileb;
- X char **output_placement;
- X{
- X char *cmd;
- X void *malloc();
- X int pipefd;
- X FILE *pipefp, *popenl();
- X char *diff_result;
- X long current_chunk_size;
- X int bytes;
- X int total;
- X
- X cmd = (char *)malloc(strlen(diff_program) + strlen(filea) + strlen(fileb) + 2);
- X if (cmd == NULL) {
- X printf("Couldn't obtain memory for diff command\n");
- X exit(1);
- X }
- X
- X pipefp = popenl(diff_program, filea, fileb, NULL, "r");
- X if (pipefp == NULL) {
- X printf("Couldn't open pipe to diff program\n");
- X exit(1);
- X }
- X pipefd = fileno(pipefp);
- X current_chunk_size = DIFF_CHUNK_SIZE;
- X diff_result = (char *) xmalloc (current_chunk_size);
- X total = 0;
- X do {
- X bytes = myread (pipefd,
- X diff_result + total,
- X current_chunk_size - total);
- X total += bytes;
- X if (total == current_chunk_size)
- X diff_result = (char *) xrealloc (diff_result, (current_chunk_size *= 2));
- X } while (bytes);
- X
- X *output_placement = diff_result;
- X pclose(pipefp);
- X return total;
- X}
- X
- X
- X/*
- X * Scan a regular diff line (consisting of > or <, followed by a
- X * space, followed by text (including nulls) up to a newline.
- X *
- X * This next routine began life as a macro and many parameters in it
- X * are used as call-by-reference values.
- X */
- Xchar *
- Xscan_diff_line (scan_ptr, set_start, set_length, limit, firstchar)
- X char *scan_ptr, **set_start;
- X int *set_length;
- X char *limit;
- X char firstchar;
- X{
- X char *line_ptr = scan_ptr + 2;
- X
- X if (!(scan_ptr[0] == (firstchar)
- X && scan_ptr[1] == ' '))
- X fatal ("Bad diff format; incorrect leading line chars");
- X
- X *set_start = line_ptr;
- X while (*line_ptr != '\n') line_ptr++;
- X
- X if (line_ptr >= limit)
- X fatal ("Bad diff format; overflow in parse");
- X
- X /* Don't include newline, but do return the beginning of the
- X next line */
- X *set_length = line_ptr - *set_start;
- X
- X return line_ptr + 1;
- X}
- X
- X/*
- X * This routine outputs a three way diff passed as a list of
- X * diff3_block's.
- X * The argument MAPPING is indexed by external file number (in the
- X * argument list) and contains the internal file number (from the
- X * diff passed). This is important because the user expects his
- X * outputs in terms of the argument list number, and the diff passed
- X * may have been done slightly differently (if the first argument in
- X * the argument list was the standard input, for example).
- X */
- Xvoid
- Xoutput_diff3 (outputfile, diff, mapping)
- X FILE *outputfile;
- X struct diff3_block *diff;
- X int mapping[3];
- X{
- X int rev_mapping[3];
- X static int eliminate[3] = { 1, 0, 0};
- X int i;
- X int oddoneout;
- X char *cp;
- X struct diff3_block *ptr;
- X int line;
- X int dontprint;
- X static int skew_increment[3] = { 2, 3, 1 }; /* 0==>2==>1==>3 */
- X
- X for (i = 0; i < 3; i++)
- X rev_mapping [mapping[i]] = i;
- X
- X for (ptr = diff; ptr; ptr = D_NEXT (ptr))
- X {
- X char x[2];
- X
- X switch (ptr->correspond)
- X {
- X case DIFF_ALL:
- X x[0] = '\0';
- X dontprint = 3; /* Print them all */
- X oddoneout = 3; /* Nobody's odder than anyone else */
- X break;
- X case DIFF_1ST:
- X case DIFF_2ND:
- X case DIFF_3RD:
- X oddoneout = rev_mapping[(int) ptr->correspond - (int) DIFF_1ST];
- X
- X x[0] = oddoneout + '1';
- X x[1] = '\0';
- X dontprint = eliminate [oddoneout];
- X break;
- X default:
- X fatal ("internal: Bad diff type passed to output");
- X }
- X fprintf (outputfile, "====%s\n", x);
- X
- X /* Go 0, 2, 1 if the first and third outputs are equivalent. */
- X for (i = 0; i < 3;
- X i = (oddoneout == 1 ? skew_increment[i] : i + 1))
- X {
- X int realfile = mapping[i];
- X int
- X lowt = D_LOWLINE (ptr, realfile),
- X hight = D_HIGHLINE (ptr, realfile);
- X
- X fprintf (outputfile, "%d:", i + 1);
- X switch (lowt - hight)
- X {
- X case 1:
- X fprintf (outputfile, "%da\n", lowt - 1);
- X break;
- X case 0:
- X fprintf (outputfile, "%dc\n", lowt);
- X break;
- X default:
- X fprintf (outputfile, "%d,%dc\n", lowt, hight);
- X break;
- X }
- X
- X if (i == dontprint) continue;
- X
- X for (line = 0; line < hight - lowt + 1; line++)
- X {
- X fprintf (outputfile, " ");
- X for (cp = D_RELNUM (ptr, realfile, line);
- X cp < (D_RELNUM (ptr, realfile, line)
- X + D_RELLEN (ptr, realfile, line));
- X cp++)
- X putc (*cp, outputfile);
- X putc ('\n', outputfile);
- X }
- X }
- X }
- X}
- X
- X/*
- X * This routine outputs a diff3 set of blocks as an ed script. This
- X * script applies the changes between file's 2 & 3 to file 1. It
- X * takes the precise format of the ed script to be output from global
- X * variables set during options processing. Note that it does
- X * destructive things to the set of diff3 blocks it is passed; it
- X * reverses their order (this gets around the problems involved with
- X * changing line numbers in an ed script).
- X *
- X * Note that this routine has the same problem of mapping as the last
- X * one did; the variable MAPPING maps from file number according to
- X * the argument list to file number according to the diff passed. All
- X * files listed below are in terms of the argument list.
- X *
- X * Also, occasionally this routine needs the real names of the files
- X * on which it works. Thus file0, file1, and file2 are the filenames
- X * passed on the command line.
- X *
- X * See options.h for documentation on the global variables which this
- X * routine pays attention to.
- X */
- Xvoid
- Xoutput_diff3_edscript (outputfile, diff, mapping, file0, file1, file2)
- X FILE *outputfile;
- X struct diff3_block *diff;
- X int mapping[3];
- X char *file0, *file1, *file2;
- X{
- X int rev_mapping[3];
- X int i;
- X int leading_dot;
- X struct diff3_block *newblock, *thisblock;
- X char *cp;
- X
- X leading_dot = 0;
- X
- X for (i = 0; i < 3; i++)
- X rev_mapping [mapping [i]] = i;
- X
- X newblock = reverse_diff3_blocklist (diff);
- X
- X for (thisblock = newblock; thisblock; thisblock = thisblock->next)
- X {
- X /* Must do mapping correctly. */
- X enum diff_type type
- X = ((thisblock->correspond == DIFF_ALL) ?
- X DIFF_ALL :
- X ((enum diff_type)
- X (((int) DIFF_1ST)
- X + rev_mapping [(int) thisblock->correspond - (int) DIFF_1ST])));
- X
- X /* If we aren't supposed to do this output block, skip it */
- X if (type == DIFF_2ND || type == DIFF_1ST
- X || (type == DIFF_3RD && dont_write_simple)
- X || (type == DIFF_ALL && dont_write_overlap))
- X continue;
- X
- X if (flagging && type == DIFF_ALL)
- X /* Do special flagging */
- X {
- X overlaps++;
- X /* Put in lines from FILE2 with bracket */
- X fprintf (outputfile, "%da\n",
- X D_HIGHLINE (thisblock, mapping [FILE0]));
- X fprintf (outputfile, "=======\n");
- X for (i = 0;
- X i < D_NUMLINES (thisblock, mapping [FILE2]);
- X i++)
- X {
- X if (D_RELNUM (thisblock, mapping[FILE2], i)[0] == '.')
- X { leading_dot = 1; fprintf(outputfile, "."); }
- X for (cp = D_RELNUM (thisblock, mapping [FILE2], i);
- X cp < (D_RELNUM (thisblock, mapping [FILE2], i)
- X + D_RELLEN (thisblock, mapping [FILE2], i));
- X cp++)
- X putc (*cp, outputfile);
- X putc ('\n', outputfile);
- X }
- X fprintf (outputfile, ">>>>>>> %s\n.\n", file2);
- X
- X /* Add in code to take care of leading dots, if necessary. */
- X if (leading_dot)
- X {
- X fprintf (outputfile, "%d,%ds/^\\.\\./\\./\n",
- X D_HIGHLINE (thisblock, mapping [FILE0]) + 1,
- X (D_HIGHLINE (thisblock, mapping [FILE0])
- X + D_NUMLINES (thisblock, mapping [FILE2])));
- X leading_dot = 0;
- X }
- X
- X /* Put in code to do initial bracket of lines from FILE0 */
- X fprintf (outputfile, "%da\n<<<<<<< %s\n.\n",
- X D_LOWLINE (thisblock, mapping[FILE0]) - 1,
- X file0);
- X }
- X else if (D_NUMLINES (thisblock, mapping [FILE2]) == 0)
- X /* Write out a delete */
- X {
- X if (D_NUMLINES (thisblock, mapping [FILE0]) == 1)
- X fprintf (outputfile, "%dd\n",
- X D_LOWLINE (thisblock, mapping [FILE0]));
- X else
- X fprintf (outputfile, "%d,%dd\n",
- X D_LOWLINE (thisblock, mapping [FILE0]),
- X D_HIGHLINE (thisblock, mapping [FILE0]));
- X }
- X else
- X /* Write out an add or change */
- X {
- X switch (D_NUMLINES (thisblock, mapping [FILE0]))
- X {
- X case 0:
- X fprintf (outputfile, "%da\n",
- X D_HIGHLINE (thisblock, mapping [FILE0]));
- X break;
- X case 1:
- X fprintf (outputfile, "%dc\n",
- X D_HIGHLINE (thisblock, mapping [FILE0]));
- X break;
- X default:
- X fprintf (outputfile, "%d,%dc\n",
- X D_LOWLINE (thisblock, mapping [FILE0]),
- X D_HIGHLINE (thisblock, mapping [FILE0]));
- X break;
- X }
- X for (i = 0;
- X i < D_NUMLINES (thisblock, mapping [FILE2]);
- X i++)
- X {
- X if (D_RELNUM (thisblock, mapping [FILE2], i)[0] == '.')
- X { leading_dot = 1; fprintf (outputfile, "."); }
- X for (cp = D_RELNUM (thisblock, mapping [FILE2], i);
- X cp < (D_RELNUM (thisblock, mapping [FILE2], i)
- X + D_RELLEN (thisblock, mapping [FILE2], i));
- X cp++)
- X putc (*cp, outputfile);
- X putc ('\n', outputfile);
- X }
- X fprintf (outputfile, ".\n");
- X
- X /* Add in code to take care of leading dots, if necessary. */
- X if (leading_dot)
- X {
- X fprintf (outputfile, "%d,%ds/^\\.\\./\\./\n",
- X D_HIGHLINE (thisblock, mapping [FILE0]) + 1,
- X (D_HIGHLINE (thisblock, mapping [FILE0])
- X + D_NUMLINES (thisblock, mapping [FILE2])));
- X leading_dot = 0;
- X }
- X }
- X }
- X if (finalwrite) fprintf (outputfile, "w\nq\n");
- X}
- X
- X/*
- X * Reverse the order of the list of diff3 blocks.
- X */
- Xstruct diff3_block *
- Xreverse_diff3_blocklist (diff)
- X struct diff3_block *diff;
- X{
- X register struct diff3_block *tmp, *next, *prev;
- X
- X for (tmp = diff, prev = (struct diff3_block *) 0;
- X tmp; tmp = next)
- X {
- X next = tmp->next;
- X tmp->next = prev;
- X prev = tmp;
- X }
- X
- X return prev;
- X}
- X
- Xint
- Xmyread (fd, ptr, size)
- X int fd, size;
- X char *ptr;
- X{
- X int result = read (fd, ptr, size);
- X if (result < 0)
- X perror_with_exit ("Read failed");
- X return result;
- X}
- X
- Xvoid *
- Xxmalloc (size)
- X int size;
- X{
- X void *result = (void *) calloc (1,size + 100);
- X if (!result)
- X fatal ("Malloc failed");
- X return result;
- X}
- X
- Xvoid *
- Xxrealloc (ptr, size)
- X void *ptr;
- X int size;
- X{
- X void *result = (void *) realloc (ptr, size);
- X if (!result)
- X fatal ("Realloc failed\n");
- X return result;
- X}
- X
- Xvoid fatal (string)
- X char *string;
- X{
- X printf("%s: %s\n",argv0, string);
- X exit (1);
- X}
- Xvoid perror_with_exit (string)
- X char *string;
- X{
- X perror (string);
- X exit (1);
- X}
- SHAR_EOF
- echo "End of archive 2 (of 14)"
- # if you want to concatenate archives, remove anything after this line
- exit
-